5

SZNUnmanagedReference クラスでメッセージ転送を使用したいと考えています。次のプロパティがあります。

@property (nonatomic, strong) NSSet *authors;
@property (nonatomic, strong) SZNReferenceDescriptor *referenceDescriptor;

基本的に、 UnmanagedReference のインスタンスがメッセージを受信すると、 という名前のメソッドを持つ にauthorsString転送する必要があります。referenceDescriptor- (NSString *)authorsStringWithSet:(NSSet *)authors

だから、私はこれを書いたSZNUnmanagedReference.m

- (void)forwardInvocation:(NSInvocation *)anInvocation {

    SEL aSelector = anInvocation.selector;

    if ([NSStringFromSelector(aSelector) isEqualToString:NSStringFromSelector(@selector(authorsString))]) {
        NSMethodSignature *signature = [self.referenceDescriptor methodSignatureForSelector:@selector(authorsStringWithSet:)];
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
        NSSet *authors = [NSSet setWithSet:self.authors];
        [invocation setSelector:@selector(authorsStringWithSet:)];
        [invocation setArgument:&authors atIndex:2];
        [invocation setTarget:self.referenceDescriptor];

        [invocation invoke];
    } else {
        [self doesNotRecognizeSelector:aSelector];
    }
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([super respondsToSelector:aSelector]) {
        return YES;
    } else if ([NSStringFromSelector(aSelector) isEqualToString:NSStringFromSelector(@selector(authorsString))] && [self.referenceDescriptor respondsToSelector:@selector(authorsStringWithSet:)]) {
        return YES;
    } else {
        return NO;
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) {  
        signature = [self.referenceDescriptor methodSignatureForSelector:@selector(authorsStringWithSet:)];
    }
    return signature;
}

SZNReferenceDescriptorすべてが機能しているように見え、クラス内のコードが実行されます。authorsStringしかし、私は背中を取得する方法がわかりません。referenceDescriptorドキュメントを正しく理解していれば、メッセージの元の送信者に結果を送り返すことになっていると思います。しかし、うまくいかないようです。私のテストクラスでは、 を[unmanagedReference authorsString]返しますnil

4

1 に答える 1

8

NSInvocation問題は、必要なポイント(メッセージディスパッチ「スタック」の「トップ」)で戻り値にアクセスできない新しいオブジェクトを作成していることです。ランタイムは、作成したものだけを認識します(forwardInvocation:;への引数は、戻り値が使用されるものです。次に、必要なのは、戻り値を設定することだけです。

- (void)forwardInvocation:(NSInvocation *)anInvocation {

    if (anInvocation.selector == @selector(authorsString)) {
        id retVal = [self.referenceDescriptor authorsStringWithSet:self.authors];

        [anInvocation setReturnValue:&retVal];   // ARC may require some memory-qualification casting here; I'm compiling this by brain at the moment
    } else {
        [super forwardInvocation:anInvocation];
    }
}

実際、その新しい呼び出しを作成する必要はありません。必要なのはメソッドの戻り値だけなので、メッセージを直接送信できます(転送メカニズムを使用するのではなく、に実装authorsStringした場合にも送信できます)。SZNUnmanagedReference

また、セレクターを文字列と比較するために文字列との間で変換する必要がないことに注意してください。sSELは、等式演算子を使用して直接比較できます。

于 2012-07-12T18:26:51.707 に答える