DevPrep

Все темы › Objective-C

Forward Invocation

Senior PRO

Место в цепочке

Когда objc_msgSend не находит реализацию селектора ни в классе, ни у предков, рантайм даёт объекту несколько шансов, от дешёвого к дорогому:

  1. +resolveInstanceMethod: — добавить метод прямо сейчас (class_addMethod).
  2. -forwardingTargetForSelector: — вернуть другой объект; сообщение уйдёт ему как есть. Дёшево: аргументы не упаковываются.
  3. -methodSignatureForSelector: + -forwardInvocation: — полное перенаправление. Рантайм спрашивает сигнатуру, упаковывает self, _cmd и аргументы в NSInvocation и отдаёт вам. Вы можете вызвать её на любом объекте, изменить аргументы, подменить селектор, залогировать, отложить, вернуть значение через setReturnValue:.
  4. Если methodSignatureForSelector: вернул nil или forwardInvocation: не переопределён — -doesNotRecognizeSelector: → NSInvalidArgumentException.

forwardInvocation: работает в паре: без methodSignatureForSelector: рантайм не знает, как разложить аргументы, и до вашего метода не дойдёт.

#import <Foundation/Foundation.h>

@interface LoggingBox : NSObject
@property (nonatomic, strong) id inner;
@end

@implementation LoggingBox
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    NSMethodSignature *sig = [super methodSignatureForSelector:sel];
    return sig ?: [self.inner methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
    if ([self.inner respondsToSelector:invocation.selector]) {
        NSLog(@"-> %@", NSStringFromSelector(invocation.selector));
        [invocation invokeWithTarget:self.inner];
    } else {
        [super forwardInvocation:invocation]; // doesNotRecognizeSelector:
    }
}
- (BOOL)respondsToSelector:(SEL)sel {
    return [super respondsToSelector:sel]
        || [self.inner respondsToSelector:sel];
}
@end

Продолжение ответа с кодом и уточняющими вопросами интервьюера — в приложении DevPrep.

Полный ответ — в DevPrep

Потренируйтесь перед собеседованием

В DevPrep эти ответы превращаются в задачи на минуту: что напечатает код, найди баг, пробное собеседование. По задаче в день.

Скачать DevPrep в App Store