将参数传递给 addTarget: action: forControlEvents

我使用的 addTarget: action: forControlEvents 是这样的:

[ newsButton addTarget: self ]
Action:@selector (switchToNewsDetails)
ForControlEvents: UIControlEventTouchUpInside ] ;

我想传递参数到我的选择器“ switchToNewsDetails”。 我唯一成功做到的就是通过写下:

action:@selector(switchToNewsDetails:)

But I am trying to pass variables like integer values. Writing it this way doesn't work :

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

Writing it this way does not work either:

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

Any help would be appreciated :)

121713 次浏览

参见我上面的注释,我相信当有多个参数时必须使用 NSInvation

更多关于 NSInvation 的信息请点击这里

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

action:@selector(switchToNewsDetails:)

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

  1. 没有参数

    action:@selector(switchToNewsDetails)
    
  2. with 1 parameter indicating the control that sends the message

    action:@selector(switchToNewsDetails:)
    
  3. With 2 parameters indicating the control that sends the message and the event that triggered the message:

    action:@selector(switchToNewsDetails:event:)
    

It is not clear what exactly you try to do, but considering you want to assign a specific details index to each button you can do the following:

  1. set a tag property to each button equal to required index
  2. in switchToNewsDetails: method you can obtain that index and open appropriate deatails:

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

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

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

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

action:@selector(switchToNewsDetails:event:)

action:@selector(switchToNewsDetails: forEvent:)

要传递自定义参数随着按钮点击你只需要 SUBCLASS UIButton

(ASR 已经开启,所以代码中没有发布。)

这是 我的扣子

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

如果您需要我更具体地介绍上述代码的任何部分,请在注释中随意提问。

我做了一个解决方案,部分基于上述信息。我只是将 titlelabel.text 设置为要传递的字符串,并设置 titlelabel.hide = YES

像这样:

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

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

我为一个数组中的每个电话号码创建了几个按钮,因此每个按钮需要一个不同的电话号码来呼叫。在 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: method 中,我使用了相同的 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]];
}
}
}

正如这里提到的许多解决方案一样,除了类别特性。

使用类别特性将已定义(内置)元素扩展到 可定制的元素可定制的元素。

例如(例如) :

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

我在 CustomButton 中子类化了 UIButton,并在存储数据的地方添加了一个属性。因此,我调用 method: (CustomButton *) sender,在该方法中,我只读取我的数据 sender.myproperty。

示例 CustomButton:

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

不仅仅需要一个(int) via. tag? 使用 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!

注意: 密钥不应该是 CALayer 属性的默认密钥,考虑为所有密钥添加一个唯一的前缀,以避免任何由密钥冲突引起的问题。


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

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


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


}

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

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

用法:

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

还有另一种方法,可以获得按下按钮的单元格的 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,它变得简单多了。

如果你只是想修改导航控制器显示的 left BarButtonItem 的文本和新视图,你可以在调用 pushViewController 之前修改当前视图的标题,然后在 viewHasDisappers 回调中恢复它,以便将来显示当前视图。

这种方法可以保持功能(popViewController)和所示箭头的外观不变。

它至少对我们的 iOS 12是有效的,它是用 Xcode 10.1构建的..。