检查 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 中执行此操作的典型方法是设置内容,以便您始终可以发送所有内容并让接收者忽略它。
就像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 中执行此操作的典型方法是设置内容,以便您始终可以发送所有内容并让接收者忽略它。