forwardInvocation:返回值丢失

Cam*_*der 5 cocoa-touch objective-c message-forwarding ios

我想在我的SZNUnmanagedReference类上使用消息转发.它有这个属性:

@property (nonatomic, strong) NSSet *authors;
@property (nonatomic, strong) SZNReferenceDescriptor *referenceDescriptor;
Run Code Online (Sandbox Code Playgroud)

基本上,当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;
}
Run Code Online (Sandbox Code Playgroud)

这一切似乎都有效,SZNReferenceDescriptor类中的代码会被执行.但是,我不知道怎么authorsString回来.如果我正确理解文档,我认为referenceDescriptor应该将结果发送回消息的原始发件人.但它似乎没有用.在我的测试课中,[unmanagedReference authorsString]返回nil.

Jos*_*ell 8

问题是你正在构造一个新NSInvocation对象,它的返回值在需要它的地方是不可访问的(消息调度"stack"的"顶部").运行时只知道它为你创建的那个(参数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];
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上,实际上没有必要创建新的调用; 因为所有你需要的是方法的返回值,你可以直接发送消息(你也可以做,如果你只是执行authorsStringSZNUnmanagedReference,而不是使用转发机制).

另外,请注意,不需要将选择器转换为字符串以及从字符串转换选择器以进行比较 - SEL可以使用等于运算符直接比较s.