129

我正在使用 addTarget:action:forControlEvents 像这样:

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

我想将参数传递给我的选择器“switchToNewsDetails”。我成功做的唯一一件事是通过编写(id)发件人:

action:@selector(switchToNewsDetails:)

但我正在尝试传递整数值等变量。这样写是行不通的:

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

以这种方式编写它也不起作用:

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

任何帮助,将不胜感激 :)

4

13 回答 13

175
action:@selector(switchToNewsDetails:)

您不在switchToNewsDetails:这里将参数传递给方法。您只需创建一个选择器以使按钮能够在发生某些操作时调用它(在您的情况下进行修饰)。控件可以使用 3 种类型的选择器来响应动作,它们都具有预定义的参数含义:

  1. 无参数

    action:@selector(switchToNewsDetails)
    
  2. 带有 1 个参数指示发送消息的控件

    action:@selector(switchToNewsDetails:)
    
  3. 有 2 个参数指示发送消息的控件和触发消息的事件:

    action:@selector(switchToNewsDetails:event:)
    

目前尚不清楚您到底想做什么,但考虑到您想为每个按钮分配一个特定的详细信息索引,您可以执行以下操作:

  1. 为每个按钮设置一个标签属性等于所需的索引
  2. switchToNewsDetails:方法中,您可以获得该索引并打开适当的详细信息:

    - (void)switchToNewsDetails:(UIButton*)sender{
        [self openDetails:sender.tag];
        // Or place opening logic right here
    }
    
于 2010-10-21T14:33:23.770 回答
64

要将自定义参数与按钮单击一起传递,您只需要SUBCLASS UIButton

(ASR 已打开,因此代码中没有版本。)

这是myButton.h

#import <UIKit/UIKit.h>

@interface myButton : UIButton {
    id userData;
}

@property (nonatomic, readwrite, retain) id userData;

@end

这是myButton.m

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

用法:

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

接收功能:

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

如果您需要我对上述代码的任何部分更具体 - 请随时在评论中询问。

于 2013-01-25T18:24:52.533 回答
20

需要的不仅仅是通过 .tag 的 (int)?使用 KVC!

您可以通过按钮对象本身传递您想要的任何数据(通过访问 CALayers keyValue dict)。


像这样设置你的目标(使用“:”)

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

将您的数据添加到按钮本身(以及按钮本身.layer),如下所示:

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!

然后,当点击按钮时,您可以像这样检查它:

-(void)buttonTap:(UIButton*)sender{

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

}
于 2016-10-14T20:43:33.773 回答
19

Target-Action 允许三种不同形式的动作选择器:

- (void)action
- (void)action:(id)sender
- (void)action:(id)sender forEvent:(UIEvent *)event
于 2010-10-21T14:33:45.893 回答
8

我部分基于上述信息提出了解决方案。我只是将 titlelabel.text 设置为我要传递的字符串,然后设置 titlelabel.hidden = YES

像这样 :

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

这样,就不需要继承或类别,也没有内存泄漏

于 2013-10-29T20:41:07.867 回答
5

我为数组中的每个电话号码创建了几个按钮,因此每个按钮都需要一个不同的电话号码来呼叫。我在 for 循环中创建了几个按钮时使用了 setTag 函数:

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

然后在我的 call: 方法中,我使用了相同的 for 循环和 if 语句来选择正确的电话号码:

- (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]];
        }
    }
}
于 2014-02-25T10:26:28.643 回答
2

由于这里提到的解决方案有很多方法,除了类别特征。

使用类别功能将定义的(内置)元素扩展到您的可自定义元素。

例如(前):

@interface UIButton (myData)

@property (strong, nonatomic) id btnData;

@end

在你的视图 Controller.m

 #import "UIButton+myAppLists.h"

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

事件处理程序:

-(void)buttonClicked : (UIButton*)sender{
    NSLog(@"my Data %@", sender. btnData);
}
于 2014-10-13T09:40:49.813 回答
2

还有另一种方法,您可以获得按下按钮的单元格的 indexPath :

使用通常的动作选择器,例如:

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

然后在你的函数中:

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

因为你得到一个 indexPath 它变得更加简单。

于 2018-04-02T15:17:27.630 回答
2

您可以通过添加一个辅助闭包包装器 (ClosureSleeve) 并将其作为关联对象添加到控件中以使其保留,从而将 target-action 替换为闭包(Objective-C 中的块)。这样你就可以传递任何参数。

斯威夫特 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)
    }
}

用法:

button.addAction(for: .touchUpInside) {
    self.switchToNewsDetails(parameter: i)
}
于 2017-07-05T05:12:58.710 回答
1

看我上面的评论,我相信当有多个参数时你必须使用 NSInvocation

更多关于 NSInvocation 的信息在这里

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

于 2010-10-21T14:27:41.473 回答
1

这解决了我的问题,但除非我改变它崩溃了

action:@selector(switchToNewsDetails:event:)                 

action:@selector(switchToNewsDetails: forEvent:)              
于 2011-02-12T14:02:36.923 回答
0

如果您只想更改导航控制器显示的 leftBarButtonItem 的文本以及新视图,您可以在调用 pushViewController 之前将当前视图的标题更改为想要的文本,并在 viewHasDisappered 回调中恢复它以供将来显示当前视图。

这种方法保持功能(popViewController)和所示箭头的外观完好无损。

它至少适用于我们使用 Xcode 10.1 构建的 iOS 12 ...

于 2018-12-11T20:35:45.073 回答
0

我在 CustomButton 中对 UIButton 进行了子类化,并添加了一个属性来存储我的数据。所以我调用方法:(CustomButton*) sender,在方法中我只读取了我的数据 sender.myproperty。

示例自定义按钮:

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

方法动作:

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

分配动作

    CustomButton *btn = [[CustomButton alloc] initWithFrame: CGRectMake(margin, margin, 60, 60)];
    // other setup…

    btnWa.textShare = @"my text";
    [btn addTarget: self action: @selector(shareWhatsapp:)  forControlEvents: UIControlEventTouchUpInside];
于 2016-05-24T00:49:02.970 回答