检查 ObjC 选择器 (SEL) 上是否有参数

Check if on ObjC selector (SEL) has a parameter

就像UIButton我可以的地方:

[button addTarget:target forSelector:@selector(action)]

或者:

[button addTarget:target forSelector:@selector(action:)]

在第二个按钮的操作将有一个发送器(即按钮本身)的位置,我如何确定给定的选择器是否有参数,以便我可以向它传递一些东西?

作为第一步,我会使用 NSStringFromSelector(). If for some reason that gave you problems, I would use sel_getName

NSInteger MYParameterCountOfSelector(SEL selector) {
    NSString *string = NSStringFromSelector(selector);
    return [string componentsSeparatedByString:@":"].count - 1;
}

Jeffery 是对的(许多动态 ObjC 是通过这种方式处理选择器而不是深入研究 NSMethodSignature 的内容,后者为您提供更精确的信息)。但同样,你总是可以传递一些东西。我知道这听起来很疯狂,但在 ObjC 中传递太多东西实际上并不是问题。

@interface MyObject: NSObject
- (void)something;
@end

...

MyObject *object = [MyObject new];
[object performSelector:@selector(something) withObject:@"thing"];

工作正常。什么!?!?是的。这实际上就是您的按钮示例的工作方式。在你的 IBAction 中放置一个断点,然后去查看调用者:

0x108b21d2c <+58>: movq   0x1400a1d(%rip), %rsi     ; "performSelector:withObject:withObject:"
0x108b21d33 <+65>: movq   %rbx, %rdi
0x108b21d36 <+68>: movq   %r12, %rdx
0x108b21d39 <+71>: movq   %r15, %rcx
0x108b21d3c <+74>: movq   %r14, %r8
0x108b21d3f <+77>: callq  *0x10ac7f3(%rip)          ; (void *)0x0000000108019ac0: objc_msgSend

它总是调用 performSelector:withObject:withObject: 并向您传递发件人和事件,即使您没有要求它们也是如此。如果您不相信我(假设您在模拟器中),请尝试查看 $rdx (arg2) 和 $rcx (arg3)。如果您想要所有正确的寄存器,您将需要 the list).来自我的 (IBAction)doThing 方法:

(lldb) po $rdx
<UIButton: 0x7f8071a126f0; frame = (164 318; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x608000223140>>

(lldb) po $rcx
<UITouchesEvent: 0x6180001068a0> timestamp: 1.06651e+06 touches: {(
    <UITouch: 0x7f8070500e20> phase: Ended tap count: 1 force: 0.000 window: <UIWindow: 0x7f8071a10890; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x60800026dbc0>; layer = <UIWindowLayer: 0x608000222800>> view: <UIButton: 0x7f8071a126f0; frame = (164 318; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x608000223140>> location in window: {205, 335} previous location in window: {205, 335} location in view: {41, 17} previous location in view: {41, 17}
)}

所以是的,您可以拆开选择器并确定要发送或不发送的内容,但在 Cocoa 中执行此操作的典型方法是设置内容,以便您始终可以发送所有内容并让接收者忽略它。