以下代码编译并运行正常(请注意sel_registerName("+")
):
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
@interface Integer : NSObject
{
NSInteger intValue;
}
@property (assign) NSInteger intValue;
@end
@implementation Integer
@synthesize intValue;
- (id) plus:(Integer*)anInteger
{
Integer* outInt = [Integer new];
[outInt setIntValue: intValue + [anInteger intValue]];
return outInt;
}
@end
int main (int argc, char const *argv[])
{
id pool = [[NSAutoreleasePool alloc] init];
SEL plusSel = sel_registerName("+");
Method m = class_getInstanceMethod([Integer class], @selector(plus:));
class_addMethod([Integer class], plusSel, method_getImplementation(m), method_getTypeEncoding(m));
Integer* i4 = [Integer new];
Integer* i20 = [Integer new];
[i4 setIntValue: 4];
[i20 setIntValue: 20];
Integer* res = objc_msgSend(i4, plusSel, i20);
NSLog(@"%d + %d = %d", [i4 intValue], [i20 intValue], [res intValue]);
// >> 4 + 20 = 24
[pool drain];
return 0;
}
除了“哎呀”之外,是否有理由对这样做持谨慎态度?
答案 0 :(得分:1)
ObjC运行时的API不太可能改变,但调用sel_registerName(“+”)的有效性可能会改变。我已经在ObjC运行时中徘徊了很多,即使经过多次更新也没有遇到任何问题。话虽这么说,我不会依靠数百万美元的业务继续工作。
答案 1 :(得分:0)
目前,Objective-C运行时库不会对您尝试注册的字符串的内容执行任何检查,开发团队也不太可能更改该行为。如果它是一个非空的C字符串,如果你总是使用objc_msgSend
为该选择器发送消息,如果你不尝试做[i4 +:i20]
之类的事情(这将导致编译错误) ),没有理由害怕。
注册的Objective-C选择器实际上是运行时系统内部存储的C字符串。运行时系统保存一个指向C字符串的指针表,即所谓的SEL集。当您调用sel_registerName
时,ObjC运行时系统会为您的字符串以及存储在SEL集中的每个C字符串调用strcmp
。如果SEL集中的任何C字符串等于您要注册的字符串,则该函数返回集合中相应C字符串的地址。否则,系统会复制您的字符串(使用strdup
),将结果指针存储在SEL集中并返回它。这个新指针成为一个新的唯一选择器。