在 object-c 中,selector 包含两种意义:在源文件中,它指向一个方法调用,在编译后它指向一个 unque indentifier。
编译后的 selector 的类型为 SEL,同名的方法的选择器也相同。
使用 selector 来调用object 方法是 Cocoa 框架 "目标-动作" 编程模型的基础。
可以使用 @selector 来为 selector 创建一个别名:
SEL setWidthHeight; setWidthHeight = @selector(setWidth:height:);
在编译时用别名方法引用 seletor 不会对性能造成大的影响。如果是运行时需要根据一个字会串动态决态调用哪个方法可以下面的形式,有点类似于反射: NSString *method; method = NSStringFromSelector(setWidthHeight);
关于方法和选择器
框架只为 selector 分配 identifier 鸸 不是方法的实现,因此不同 class 的同名方法虽然 selector 的 identifier 一样,但是在执行是与方法调用无异。同时静态方法也可以与动态方法重名,因为他们有不同的归属对象。
动态类型标注时,同名方法必须是相同的参数类型与返回值,而静态类型标注时不需要。这是因为静态类型标注时可以通过类的元数据得知方法的实现。
除此之外,静态方法和实例方法也不受此限制,他们存在于不同的空间。
id helper = getTheReceiver(); SEL request = getTheSelector(); [helper performSelector:request];
如些的动态调用显得很强大。
[myButtonCell setAction:@selector(reapTheWind:)]; [myButtonCell setTarget:anObject];
上面的代码演示了如何将按钮和事件处理对象进行关联
虽然有一些手段使用动态 message 来维护按钮与事件处理对象的关系,但是苹果认为那会带来不必要的复杂性,因此使用了目前这种方式。
为了避免对象接受到它不能处理的消息,多用静态标注类型总是好的,因为它可以在编译时被检查。
如果一定要在运行时调用一个不能确定的方法,那么可以用这样的方式进行测试,以进行安全调用而不是报错:
if ( [anObject respondsToSelector:@selector(setOrigin::)] ) [anObject setOrigin:0.0 :0.0]; else fprintf(stderr, "%s can’t be placed\n", [NSStringFromClass([anObject class]) UTF8String]);
另外,当对象不能处理一个消息时,它可以对它进行转发。详见 消息转发: http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105
|
请发表评论