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 に答える