iOS中@selector的runtime过程
大家都知道oc是动态语言,是runtime的,怎么体现他的动态性呢,今天用SEL来分析下,之前分享过钩子其实就可以看出来了,现在具体看看OC是怎么通过SEL找到函数的。
[self performSelector:@selector(abcd)]; [self abcd]; //这种方法可能都会编译不过去
假如类方法里面我们便没有写adcd方法,这样就会奔溃了,oc是怎么做的呢
该方法调用后,OC会发出objc_msgSend,将消息传给本来查找本类中的SEL是否存在Method
假设本类不存在会查找工程里是否有分类提供了该方法
假设分类中也没有该方法,系统会将消息转发给其父类,父类收到消息后也会执行上面的操作,找方法,没找到再往上转发消息
假设最终都没有找到,就会执行最后的消息转发(message forwarding)操作
如果转发出去都没人接收的话,NSObject中的doesNotRecognizeSelector就选择抛出异常了,也就是我们看到的crash
上面的过程有点复杂,大家会觉得这样很慢,第一次的确很慢,所性objc_msgSend会将匹配结果写到映射表中缓存起来,每个类都有这样的一块缓存
整个过程就是上面将的那样,我们讲一下第4项消息转发怎么处理吧:
消息转发还分两个阶段:
1.动态方法解析:意思就是说询问接受者要不要增加个方法来实现该函数
+ (BOOL)resolveInstanceMethod:(SEL)selecotor //对象方法 + (BOOL)resolveClassMethod:(SEL)sel //类方法
在方法里可以动态给类增加一个方法Method
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self performSelector:@selector(abcd)]; } + (BOOL)resolveInstanceMethod:(SEL)sel { NSString *selname = NSStringFromSelector(sel); if ([selname isEqualToString:@"abcd"]) { class_addMethod(self, sel, class_getMethodImplementation([self class], @selector(oklala)), method_getTypeEncoding(class_getInstanceMethod([self class], @selector(oklala)))); return YES; } return [super resolveInstanceMethod:sel]; } - (void)oklala { NSLog(@"oklala"); }
2.完整的消息转发:看看还有没有别的对象要处理,有转出,没有的话封装成NSInvocation对象处理
1)假如可以转给别的对象处理:
- (id)forwardingTargetForSelector:(SEL)aSelector
可以将要转发的对象返回。
@interface abcdCaller : NSObject @end @implementation abcdCaller - (void)abcd { NSLog(@"~~~~~~"); } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self performSelector:@selector(abcd)]; } - (id)forwardingTargetForSelector:(SEL)aSelector { NSLog(@"!!!!!!!!!!!!!"); return [[abcdCaller alloc] init]; } @end
2)假如没有对象可以转发(完整消息转发)
- (void)forwardInvocation:(NSInvocation *)anInvocation
最后可以处理消息的机会
假设你的消息转发不处理,那么在第5步捕获异常,也是不会奔溃的
@try { [self performSelector:@selector(abcd)]; } @catch (NSException *exception) { NSLog(@"~~~~~~~~"); } @finally { }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。