DevPrep

All topics › Objective-C

Forward invocation

Senior PRO

Place in the chain

When objc_msgSend finds no implementation of a selector in the class or its ancestors, the runtime gives the object several chances, from cheap to expensive:

  1. +resolveInstanceMethod: — add the method right now (class_addMethod).
  2. -forwardingTargetForSelector: — return another object; the message goes to it as is. Cheap: arguments are not packed.
  3. -methodSignatureForSelector: + -forwardInvocation: — full forwarding. The runtime asks for the signature, packs self, _cmd and the arguments into an NSInvocation and hands it to you. You can invoke it on any object, change arguments, swap the selector, log, defer, or return a value via setReturnValue:.
  4. If methodSignatureForSelector: returned nil or forwardInvocation: is not overridden — -doesNotRecognizeSelector: → NSInvalidArgumentException.

forwardInvocation: works as a pair: without methodSignatureForSelector: the runtime does not know how to lay out the arguments and never reaches your method.

#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

The rest of this answer, with code and interview follow-ups, is in the DevPrep app.

Read the full answer in DevPrep

Practice this before your interview

DevPrep turns these answers into one-minute challenges: what does this code print, find the bug, mock interviews. One challenge a day.

Get DevPrep on the App Store