Passando parâmetros para addTarget: action: forControlEvents

Eu estou usando addTarget: action: forControlEvents como este:

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

e gostaria de passar parâmetros ao meu seletor “switchToNewsDetails”. A única coisa que consigo fazer é passar o remetente (id) escrevendo:

 action:@selector(switchToNewsDetails:) 

Mas estou tentando passar variables ​​como valores inteiros. Escrever dessa maneira não funciona:

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

Escrevendo desta forma não funciona:

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

Qualquer ajuda seria apreciada 🙂

 action:@selector(switchToNewsDetails:) 

Você não passa parâmetros para o método switchToNewsDetails: aqui. Você acabou de criar um seletor para tornar o botão capaz de chamá-lo quando ocorrer alguma ação (retocar no seu caso). Os controles podem usar 3 tipos de seletores para responder às ações, todos eles têm um significado predefinido de seus parâmetros:

  1. sem parâmetros

     action:@selector(switchToNewsDetails) 
  2. com 1 parâmetro indicando o controle que envia a mensagem

     action:@selector(switchToNewsDetails:) 
  3. Com 2 parâmetros indicando o controle que envia a mensagem e o evento que acionou a mensagem:

     action:@selector(switchToNewsDetails:event:) 

Não está claro o que exatamente você tenta fazer, mas considerando que você deseja atribuir um índice de detalhes específico para cada botão, você pode fazer o seguinte:

  1. definir uma propriedade de tag para cada botão igual ao índice exigido
  2. switchToNewsDetails: método switchToNewsDetails: você pode obter esse índice e abrir deatails apropriados:

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

Para passar parâmetros personalizados junto com o botão, você só precisa SUBCLASS UIButton .

(ASR está ativado, então não há lançamentos no código.)

Isso é myButton.h

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

Este é o 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]; 

Função de recepção:

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

Se você precisar que eu seja mais específico em qualquer parte do código acima – sinta-se à vontade para perguntar sobre isso nos comentários.

O Target-Action permite três formas diferentes de seletor de ação:

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

Você pode passar qualquer dado que desejar através do próprio object de botão (acessando o keyValue dict de CALayers).


Defina o seu alvo assim (com o “:”)

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

Adicione seus dados ao botão em si (assim como a .layer do botão):

 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! 

Então, quando o botão é tocado, você pode checar assim:

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

Eu fiz uma solução baseada em parte pelas informações acima. Acabei de definir o titlelabel.text para a string que quero passar e definir o titlelabel.hidden = YES

Como isso :

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

Desta forma, não há necessidade de uma inheritance ou categoria e não há memory leaks

Eu estava criando vários botões para cada número de telefone em uma matriz para que cada botão precisava de um número de telefone diferente para ligar. Eu usei a function setTag como eu estava criando vários botões dentro de um loop 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]; } 

Então, na minha chamada: método eu usei o mesmo loop e uma declaração if para escolher o número de telefone correto:

 - (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 há muitas maneiras mencionadas aqui para a solução, exceto o recurso de categoria.

Use o recurso de categoria para estender o elemento definido (interno) em seu elemento personalizável.

Por exemplo (ex):

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

na sua opinião Controller.m

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

Manipulador de events:

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

Existe outro caminho, no qual você pode obter indexPath da célula onde o botão foi pressionado:

usando o seletor de ação normal como:

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

e depois na sua function:

  - (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 você obtenha um indexPath, ele se torna muito mais simples.

Veja meu comentário acima, e acredito que você tenha que usar o NSInvocation quando houver mais de um parâmetro

mais informações sobre NSInvocation aqui

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

Isso resolveu meu problema, mas ele caiu a menos que eu mudei

 action:@selector(switchToNewsDetails:event:) 

para

 action:@selector(switchToNewsDetails: forEvent:) 

Você pode replace a ação de destino por um encerramento (bloco em Objective-C) adicionando um wrapper de fechamento auxiliar (ClosureSleeve) e adicionando-o como um object associado ao controle, para que ele seja retido. Dessa forma você pode passar qualquer 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) } 

Eu subclass o UIButton no CustomButton e adiciono uma propriedade onde armazeno meus dados. Então eu chamo método: (CustomButton *) remetente e no método eu só leio meus dados sender.myproperty.

Exemplo CustomButton:

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

Ação do método:

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

Atribuir ação

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