Pasar parámetros a addTarget: action: forControlEvents

Estoy usando addTarget: action: forControlEvents como este:

[newsButton addTarget:self action:@selector(switchToNewsDetails) forControlEvents:UIControlEventTouchUpInside]; 

y me gustaría pasar parámetros a mi selector “switchToNewsDetails”. Lo único que logro hacer es pasar el (id) remitente escribiendo:

 action:@selector(switchToNewsDetails:) 

Pero estoy tratando de pasar variables como valores enteros. Escribirlo de esta manera no funciona:

 int i = 0; [newsButton addTarget:self action:@selector(switchToNewsDetails:i) forControlEvents:UIControlEventTouchUpInside]; 

Escribirlo de esta manera tampoco funciona:

 int i = 0; [newsButton addTarget:self action:@selector(switchToNewsDetails:i:) forControlEvents:UIControlEventTouchUpInside]; 

Cualquier ayuda sería apreciada 🙂

 action:@selector(switchToNewsDetails:) 

No pasa los parámetros al método switchToNewsDetails: aquí. Usted acaba de crear un selector para que el botón pueda llamarlo cuando ocurra determinada acción (retoque en su caso). Los controles pueden usar 3 tipos de selectores para responder a las acciones, todos ellos tienen un significado predefinido de sus parámetros:

  1. sin parámetros

     action:@selector(switchToNewsDetails) 
  2. con 1 parámetro que indica el control que envía el mensaje

     action:@selector(switchToNewsDetails:) 
  3. Con 2 parámetros que indican el control que envía el mensaje y el evento que desencadenó el mensaje:

     action:@selector(switchToNewsDetails:event:) 

No está claro qué es exactamente lo que intenta hacer, pero teniendo en cuenta que desea asignar un índice de detalles específicos para cada botón, puede hacer lo siguiente:

  1. establecer una propiedad de etiqueta para cada botón igual al índice requerido
  2. en el método switchToNewsDetails: puede obtener ese índice y abrir deatails apropiados:

     - (void)switchToNewsDetails:(UIButton*)sender{ [self openDetails:sender.tag]; // Or place opening logic right here } 

Para pasar parámetros personalizados junto con el botón clic, solo necesita SUBCLASS UIButton .

(ASR está activado, por lo que no hay versiones en el código).

Este es myButton.h

 #import  @interface myButton : UIButton { id userData; } @property (nonatomic, readwrite, retain) id userData; @end 

Este es myButton.m

 #import "myButton.h" @implementation myButton @synthesize userData; @end 

Uso:

 myButton *bt = [myButton buttonWithType:UIButtonTypeCustom]; [bt setFrame:CGRectMake(0,0, 100, 100)]; [bt setExclusiveTouch:NO]; [bt setUserData:**(insert user data here)**]; [bt addTarget:self action:@selector(touchUpHandler:) forControlEvents:UIControlEventTouchUpInside]; [view addSubview:bt]; 

Función de recepción:

 - (void) touchUpHandler:(myButton *)sender { id userData = sender.userData; } 

Si necesita que sea más específico en cualquier parte del código anterior, siéntase libre de preguntar al respecto en los comentarios.

Target-Action permite tres formas diferentes de selector de acción:

 - (void)action - (void)action:(id)sender - (void)action:(id)sender forEvent:(UIEvent *)event 

Puede pasar cualquier información que desee a través del botón de objeto en sí (al acceder a CALayers keyValue dict).


Establece tu objective así (con el “:”)

 [myButton addTarget:self action:@selector(buttonTap:) forControlEvents:UIControlEventTouchUpInside]; 

Agregue su (s) datos al botón mismo (y al .layer del botón que es) así:

 NSString *dataIWantToPass = @"this is my data";//can be anything, doesn't have to be NSString [myButton.layer setValue:dataIWantToPass forKey:@"anyKey"];//you can set as many of these as you'd like too! 

Luego, cuando se toca el botón, puedes verificarlo así:

 -(void)buttonTap:(UIButton*)sender{ NSString *dataThatWasPassed = (NSString *)[sender.layer valueForKey:@"anyKey"]; NSLog(@"My passed-thru data was: %@", dataThatWasPassed); } 

Hice una solución basada en parte por la información anterior. Acabo de establecer titlelabel.text en la cadena que quiero pasar, y establecí titlelabel.hidden = YES

Me gusta esto :

 UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; imageclick.frame = photoframe; imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension]; imageclick.titleLabel.hidden = YES; 

De esta manera, no hay necesidad de una herencia o categoría y no hay pérdida de memoria

Estaba creando varios botones para cada número de teléfono en una matriz, por lo que cada botón necesitaba un número de teléfono diferente para llamar. Usé la función setTag ya que estaba creando varios botones dentro de un ciclo for:

 for (NSInteger i = 0; i < _phoneNumbers.count; i++) { UIButton *phoneButton = [[UIButton alloc] initWithFrame:someFrame]; [phoneButton setTitle:_phoneNumbers[i] forState:UIControlStateNormal]; [phoneButton setTag:i]; [phoneButton addTarget:self action:@selector(call:) forControlEvents:UIControlEventTouchUpInside]; } 

Luego, en mi llamada: método, utilicé el mismo bucle y una instrucción if para elegir el número de teléfono correcto:

 - (void)call:(UIButton *)sender { for (NSInteger i = 0; i < _phoneNumbers.count; i++) { if (sender.tag == i) { NSString *callString = [NSString stringWithFormat:@"telprompt://%@", _phoneNumbers[i]]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:callString]]; } } } 

Como hay muchas maneras mencionadas aquí para la solución, excepto la función de categoría.

Use la función de categoría para extender el elemento definido (incorporado) en su elemento personalizable.

Por ejemplo (ex):

 @interface UIButton (myData) @property (strong, nonatomic) id btnData; @end 

en su vista Controller.m

  #import "UIButton+myAppLists.h" UIButton *myButton = // btn intialisation.... [myButton set btnData:@"my own Data"]; [myButton addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; 

Controlador de eventos:

 -(void)buttonClicked : (UIButton*)sender{ NSLog(@"my Data %@", sender. btnData); } 

Hay otra manera, en la que puede obtener indexPath de la celda donde se presionó su botón:

usando el selector de acción habitual como:

  UIButton *btn = ....; [btn addTarget:self action:@selector(yourFunction:) forControlEvents:UIControlEventTouchUpInside]; 

y luego en tuFunción:

  - (void) yourFunction:(id)sender { UIButton *button = sender; CGPoint center = button.center; CGPoint rootViewPoint = [button.superview convertPoint:center toView:self.tableView]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rootViewPoint]; //the rest of your code goes here .. } 

desde que obtienes un indexPath se vuelve mucho más simple.

Mira mi comentario anterior, y creo que debes usar NSInvocation cuando hay más de un parámetro

más información sobre NSInvocation aquí

http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html

Esto solucionó mi problema, pero se bloqueó a menos que cambiara

 action:@selector(switchToNewsDetails:event:) 

a

 action:@selector(switchToNewsDetails: forEvent:) 

Puede reemplazar la acción objective con un cierre (bloque en Objective-C) agregando un contenedor de cierre auxiliar (ClosureSleeve) y agregándolo como un objeto asociado al control para que se conserve. De esa forma puedes pasar cualquier parámetro.

Swift 3

 class ClosureSleeve { let closure: () -> () init(attachTo: AnyObject, closure: @escaping () -> ()) { self.closure = closure objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN) } @objc func invoke() { closure() } } extension UIControl { func addAction(for controlEvents: UIControlEvents, action: @escaping () -> ()) { let sleeve = ClosureSleeve(attachTo: self, closure: action) addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents) } } 

Uso:

 button.addAction(for: .touchUpInside) { self.switchToNewsDetails(parameter: i) } 

Subclité UIButton en CustomButton y agregué una propiedad donde almacenaba mis datos. Así que llamo al método: (CustomButton *) al remitente y en el método solo leo mis datos sender.myproperty.

Ejemplo CustomButton:

 @interface CustomButton : UIButton @property(nonatomic, retain) NSString *textShare; @end 

Acción del método:

 + (void) share: (CustomButton*) sender { NSString *text = sender.textShare; //your work… } 

Asignar acción

  CustomButton *btn = [[CustomButton alloc] initWithFrame: CGRectMake(margin, margin, 60, 60)]; // other setup… btnWa.textShare = @"my text"; [btn addTarget: self action: @selector(shareWhatsapp:) forControlEvents: UIControlEventTouchUpInside];