forwardInvocation: возвращаемое значение теряется

Я хочу использовать пересылку сообщений в моем классе 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,

1 ответ

Решение

Проблема в том, что вы создаете новый 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вместо использования механизма пересылки).

Кроме того, обратите внимание, что нет необходимости преобразовывать селекторы в строки и из строк для их сравнения - SELs можно сравнивать напрямую, используя оператор равенства.

Другие вопросы по тегам