objc向一个对象发送消息时,发生了什么?
根据对象的isa指针找到该对象所属的类,去obj的对应的类中找方法
1.首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行。
2.如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行
3.如果没找到,去父类指针所指向的对象中执行1,2.
4.以此类推,如果一直到根类还没找到,转向拦截调用,走消息转发机制。
5.如果没有重写拦截调用的方法,程序报错。
objc中向一个nil对象发送消息将会发生什么?
如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。也不会崩溃。
如果寻找不到相应的方法,会如何进行后续处理 ?
转向拦截调用。如果没有重写拦截调用的方法,程序报错。
拦截调用就是,在找不到调用的方法程序崩溃之前,你有机会通过重写NSObject的四个方法来处理。
方案一:
- (BOOL)resolveInstanceMethod:(SEL)sel
- (BOOL)resolveClassMethod:(SEL)sel
方案二: - (id)forwardingTargetForSelector:(SEL)aSelector
方案三: - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
-
(void)forwardInvocation:(NSInvocation *)anInvocation;
1448535-f50463d32de94289.jpg
上图显示了消息转发的具体流程,接收者在每一步中均有机会处理消息。步骤越往后处理消息的代价越大。首先,会调用
- (BOOL)resolveInstanceMethod:(SEL)sel。
若方法返回YES,则表示可以处理该消息。在这个过程,可以动态地给消息增加方法。
id ForwardingTarget_dynamicMethod(id self, SEL _cmd) {
NSLog(@"没有找到方法:%@",NSStringFromSelector(_cmd));
return [NSNull null];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
class_addMethod(self.class, sel, (IMP)ForwardingTarget_dynamicMethod, "@@:");
[super resolveInstanceMethod:sel];
return YES;
}
调用
People *people = [[People alloc] init];
[people performSelector:@selector(speak)];
若方法返回NO,则进行消息转发的第二步,查找是否有其它的接收者。对应的处理函数是:
- (id)forwardingTargetForSelector:(SEL)aSelector。
可以通过该函数返回一个可以处理该消息的对象。
现在新建一个类MsgForwarding,在MsgForwarding中实现一个speak方法.
MsgForwarding.m
- (void)speak
{
NSLog(@"MsgForwarding method speak called");
}
然后在People类中实现
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSString *selStr = NSStringFromSelector(aSelector);
if ([selStr isEqualToString:@"speak"]) {
// 这里返回MsgForwarding类对象,让MsgForwarding类去处理speak消息
return [[MsgForwarding alloc] init];
}
return [super forwardingTargetForSelector: aSelector];
}
若第二步返回nil,则进入消息转发的第三步。调用
*- (void)forwardInvocation:(NSInvocation )anInvocation。
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
// 新建需要转发消息的对象
MsgForwarding *msgForwarding = [[MsgForwarding alloc] init];
if ([msgForwarding respondsToSelector:selector]) {
// 唤醒这个方法
[anInvocation invokeWithTarget:msgForwarding];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(speak)) {
return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
网友评论