面试题答案
一键面试动态方法解析
- 类方法解析:当向一个对象发送一条它无法识别的消息时,运行时首先会调用类方法
+ (BOOL)resolveClassMethod:(SEL)sel
。如果在这个方法中为该SEL
动态添加了实现,消息转发就结束,对象能够响应这个消息。例如:
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(someClassMethod)) {
class_addMethod(self, sel, (IMP)someClassMethodImplementation, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
- 实例方法解析:如果类方法解析没有处理该消息,运行时会调用实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
。同样,如果在此方法中为SEL
动态添加了实现,消息转发结束。例如:
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(someInstanceMethod)) {
class_addMethod(self, sel, (IMP)someInstanceMethodImplementation, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
备用接收者
- 如果动态方法解析阶段没有处理该消息,运行时会进入备用接收者阶段。它会调用对象的
- (id)forwardingTargetForSelector:(SEL)aSelector
方法。 - 在这个方法中,对象可以返回一个能够处理该
SEL
的其他对象。如果返回非nil
对象,那么运行时会将消息发送给这个备用接收者,消息转发流程结束。例如:
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(someMethod)) {
return someOtherObject;
}
return nil;
}
完整的消息转发流程
- 动态方法解析:运行时首先尝试在类的方法列表中查找方法实现,如果找不到,会触发动态方法解析,先尝试类方法解析
+ (BOOL)resolveClassMethod:(SEL)sel
,再尝试实例方法解析+ (BOOL)resolveInstanceMethod:(SEL)sel
。 - 备用接收者:若动态方法解析未处理消息,运行时调用
- (id)forwardingTargetForSelector:(SEL)aSelector
寻找备用接收者。若找到,则将消息转发给备用接收者。 - 完整转发:如果备用接收者也未处理消息,运行时会进入完整转发阶段。首先调用
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
,该方法需要返回一个NSMethodSignature
对象,描述方法的参数和返回值类型。如果返回nil
,则会调用- (void)doesNotRecognizeSelector:(SEL)aSelector
,抛出异常表明对象无法识别该消息。若返回了有效的NSMethodSignature
,则会接着调用- (void)forwardInvocation:(NSInvocation *)anInvocation
。在这个方法中,可以修改NSInvocation
对象,指定新的目标对象来处理该消息,然后调用[anInvocation invoke]
来执行消息。例如:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(someMethod)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = anInvocation.selector;
if ([someOtherObject respondsToSelector:sel]) {
[anInvocation setTarget:someOtherObject];
[anInvocation invoke];
} else {
[super forwardInvocation:anInvocation];
}
}
整个消息转发机制为 Objective - C 提供了强大的灵活性,允许在运行时动态处理未识别的消息。