4

以下代码编译并运行良好(注意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;
}

除了“呸”之外,还有什么理由要谨慎这样做吗?

4

2 回答 2

1

ObjC 运行时的 API 不太可能改变,但调用 sel_registerName("+") 的有效性可能会改变。我经常在 ObjC 运行时中胡思乱想,即使经过多次更新也没有遇到任何问题。话虽如此,我不会将数百万美元的业务建立在这种持续工作的基础上。

于 2011-06-14T19:20:04.177 回答
0

目前,Objective-C 运行时库不对您尝试注册的字符串的内容执行任何检查,开发团队不太可能更改该行为。如果它是一个非空的 C 字符串,如果您总是使用objc_msgSend为该选择器发送消息并且如果您不尝试做类似的事情[i4 +:i20](这将导致编译错误),那么没有理由害怕。

注册的 Objective-C 选择器实际上是运行时系统内部存储的 C 字符串。运行时系统保存一个指向 C 字符串的指针表,即所谓的 SEL 集。当您调用sel_registerNameObjC 运行时系统调用strcmp您的字符串和 SEL 集中存储的每个 C 字符串。如果 SEL 集中的任何 C 字符串等于您要注册的那个,该函数将返回该集中相应 C 字符串的地址。否则,系统会复制您的字符串(使用strdup),将结果指针存储在 SEL 集中并返回它。这个新指针成为一个新的唯一选择器。

于 2013-03-25T18:45:53.267 回答