Passare i parametri ad addTarget: action: forControlEvents

Sto usando addTarget: action: forControlEvents come questo:

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

e vorrei passare i parametri al mio selettore “switchToNewsDetails”. L’unica cosa che riesco a fare è passare il mittente (id) scrivendo:

 action:@selector(switchToNewsDetails:) 

Ma sto cercando di passare variabili come valori interi. La scrittura in questo modo non funziona:

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

Scriverlo in questo modo non funziona neanche:

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

Qualsiasi aiuto sarebbe apprezzato 🙂

 action:@selector(switchToNewsDetails:) 

Non si passano i parametri a switchToNewsDetails: metodo qui. Basta creare un selettore per rendere il pulsante in grado di chiamarlo quando si verifica una determinata azione (ritoccare nel tuo caso). I controlli possono utilizzare 3 tipi di selettori per rispondere alle azioni, tutti hanno un significato predefinito dei loro parametri:

  1. senza parametri

     action:@selector(switchToNewsDetails) 
  2. con 1 parametro che indica il controllo che invia il messaggio

     action:@selector(switchToNewsDetails:) 
  3. Con 2 parametri che indicano il controllo che invia il messaggio e l’evento che ha triggersto il messaggio:

     action:@selector(switchToNewsDetails:event:) 

Non è chiaro cosa esattamente cerchi di fare, ma considerando che vuoi assegnare un indice di dettagli specifico a ciascun pulsante puoi fare quanto segue:

  1. imposta una proprietà tag per ogni pulsante uguale all’indice richiesto
  2. in switchToNewsDetails: metodo è ansible ottenere tale indice e aprire deatails appropriati:

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

Per passare parametri personalizzati con il clic del pulsante è sufficiente SUBORDINARE UIButton .

(L’ASR è attivo, quindi non ci sono versioni nel codice.)

Questo è myButton.h

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

Questo è 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]; 

Funzione di ricezione:

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

Se hai bisogno che io sia più specifico su qualsiasi parte del codice precedente, non esitare a chiedere informazioni nei commenti.

Target-Action consente tre diverse forms di selettore di azioni:

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

È ansible passare tutti i dati desiderati attraverso l’object pulsante stesso (accedendo a CALayers keyValue dict).


Imposta il tuo objective in questo modo (con “:”)

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

Aggiungi i tuoi dati al pulsante stesso (bene lo .layer del pulsante) in questo modo:

 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! 

Quindi, quando si tocca il pulsante, è ansible controllarlo in questo modo:

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

Ho fatto una soluzione basata in parte dalle informazioni di cui sopra. Ho appena impostato il titlelabel.text sulla stringa che voglio passare e ho impostato il titlelabel.hidden = YES

Come questo :

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

In questo modo, non c’è bisogno di ereditarietà o categoria e non c’è perdita di memoria

Stavo creando diversi pulsanti per ogni numero di telefono in un array, quindi ogni pulsante necessitava di un numero di telefono diverso da chiamare. Ho usato la funzione setTag mentre stavo creando diversi pulsanti all’interno di 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]; } 

Poi nella mia chiamata: metodo ho usato lo stesso ciclo e un'istruzione if per scegliere il numero di telefono corretto:

 - (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]]; } } } 

Poiché ci sono molti modi menzionati qui per la soluzione, tranne la funzione di categoria.

Usa la funzione di categoria per estendere l’elemento (incorporato) definito nel tuo elemento personalizzabile.

Ad esempio (ex):

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

nella tua 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]; 

Gestore di eventi:

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

C’è un altro modo, in cui è ansible ottenere indexPath della cella in cui è stato premuto il pulsante:

usando il solito selettore di azioni come:

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

e poi in yourFunction:

  - (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 .. } 

dato che ottieni un indicePath diventa molto più semplice.

Vedi il mio commento sopra, e credo che devi usare NSInvocation quando c’è più di un parametro

ulteriori informazioni su NSInvocation qui

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

Questo ha risolto il mio problema ma si è bloccato a meno che non fossi cambiato

 action:@selector(switchToNewsDetails:event:) 

a

 action:@selector(switchToNewsDetails: forEvent:) 

È ansible sostituire l’azione di destinazione con una chiusura (blocco in Objective-C) aggiungendo un wrapper di chiusura helper (ClosureSleeve) e aggiungendolo come object associato al controllo in modo che venga mantenuto. In questo modo puoi passare qualsiasi parametro.

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) } 

Ho sottoclass UIButton in CustomButton e aggiungo una proprietà in cui memorizzo i miei dati. Quindi chiamo metodo: (CustomButton *) mittente e nel metodo leggo solo i miei dati sender.myproperty.

Esempio CustomButton:

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

Azione del metodo:

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

Assegna l’azione

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