- 问题:什么时候会报unrecognized selector的异
- Unrecognized selector 的异常?
- 什么时候会报unrecognized selector错误?iO
- iOS Runtime面试题(什么时候会报unrecognize
- 什么时候会报unrecognized selector的异常?
- OC unrecognized selector异常
- 什么时候会报unrecognized selector异常?
- 什么时候会报unrecognized selector的异常?
- 什么时候会报 Unrecognized selector 的异常
- 什么时候会报unrecognized selector的异常
-
当调用该对象上某个方法,而该对象上没有实现这个方法的时候, 可以通过“消息转发”进行解决,如果还是不行就会报unrecognized selector异常
-
objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector),整个过程介绍如下:
-
objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类然后在该类中的方法列表以及其父类方法列表中寻找方法运行 如果,在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 。但是在这之前,objc的运行时会给出三次拯救程序崩溃的机会:
1. Method resolution
调用resolveInstanceMethod:方法 (或 resolveClassMethod:)。允许用户在此时为该 Class 动态添加实现。如果有实现了,则调用并返回YES,那么重新开始objc_msgSend流程。这一次对象会响应这个选择器,一般是因为它已经调用过class_addMethod。如果仍没实现,继续下面的动作。
+ (BOOL)resolveInstanceMethod:(SEL)sel __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0) { class_addMethod(self.class, sel, (IMP)dynamicMethodIMP, "@@:"); BOOL rslt = [super resolveInstanceMethod:sel]; rslt = YES; return rslt; // 1 }
2. Fast forwarding
调用forwardingTargetForSelector:方法,尝试找到一个能响应该消息的对象。如果获取到,则直接把消息转发给它,返回非 nil 对象。否则返回 nil ,继续下面的动作。注意,这里不要返回 self ,否则会形成死循环。
- (id)forwardingTargetForSelector:(SEL)aSelector __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0) { id rslt = [super forwardingTargetForSelector:aSelector]; rslt = self.target; return rslt; // 2 }
3. Normal forwarding
调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation。
调用forwardInvocation:方法,将上面获取到的方法签名包装成 Invocation 传入,如何处理就在这里面了,并返回非ni。//OBJC_SWIFT_UNAVAILABLE("") - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { id rslt = [super methodSignatureForSelector:aSelector]; NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:"v@:"]; rslt = sig; return rslt; // 3 } //OBJC_SWIFT_UNAVAILABLE("") (void)forwardInvocation:(NSInvocation *)anInvocation { // [super forwardInvocation:anInvocation]; [self.target forwardInvocation:anInvocation]; }
调用doesNotRecognizeSelector: ,默认的实现是抛出异常。如果上面没能获得一个方法签名,执行该步骤。
- (void)doesNotRecognizeSelector:(SEL)aSelector { // 在crash前 保存crash数据,供分析 [super doesNotRecognizeSelector:aSelector]; // crash }
网友评论