什么时候会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?

什么时候会报unrecognized selector错误?

  1. 对象未实现该方法。
  2. 对象已经被释放。

iOS有哪些机制来避免走到这一步?

  1. 使用[id respondsToSelector:]进行判断。


    forward.jpeg

    2.Method resolution
    objc运行时会调用+resolveInstanceMethod:或者 +resolveClassMethod:,让你有机会提供一个函数实现。如果你添加了函数,那运行时系统就会重新启动一次消息发送的过程,否则 ,运行时就会移到下一步,消息转发(Message Forwarding)。
    返回Nil和self,去调用第三步methodSignatureForSelector和forwarInvocation;返回receiver,如果receiver有响应就直接处理,如果没有就去对应的对象内去调用第三步;调用子类的函数,子类没有进行这几个方法的重载,在父类处理时返回子类,会死循环。
    3.Fast forwarding
    如果目标对象实现了-forwardingTargetForSelector:,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会。 只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,当然发送的对象会变成你返回的那个对象。否则,就会继续Normal Fowarding。 这里叫Fast,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但下一步转发会创建一个NSInvocation对象,所以相对更快点。
    4.Normal forwarding
    这一步是Runtime最后一次给你挽救的机会。首先它会发送-methodSignatureForSelector:消息获得函数的参数和返回值类型。如果-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象。

- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");

文档翻译:

-(id)forwardingTargetForSelector:(SEL)aSelector

返回无法识别的消息应当首先被引导到的对象。
Parameters 一个接收者没有实现的方法的选择器。
Return Value 无法识别消息应该首先被导向到的对象。
Discussion
如果一个对象实现(或者继承)了这个方法,和返回一个非空(non-self)的结果,那么返回的这个对象被用作新的接收对象和消息分发到这个新对象。(明显地,如果你从这个方法返回self,代码将进入一个无限循环中注:调试测试发现不会死循环,而是直接崩溃
如果你在一个non-root类实现这个方法,如果你的类对于这个被给的选择器没有什么东西返回,那么你应该返回调用super的实现的结果。
这方法给一个对象在调用花费更多的forwardInvocation:接管之前,重定向1个未知消息到它的一个机会。这是有用的当你简单的想重定向消息到另一个对象时和能比常规的转发快一个数量级。当转发的目标是在转发期间捕获NSInvocation或者篡改参数或者返回值时,它是没用的。

-(void)forwardInvocation:(NSInvocation *)anInvocation;

通过子类重载转发消息到其它对象。
Discussion

When an object is sent a message for which it has no corresponding method, the runtime system gives the receiver an opportunity to delegate the message to another receiver. It delegates the message by creating an NSInvocation object representing the message and sending the receiver a forwardInvocation: message containing this NSInvocation object as the argument. The receiver’s forwardInvocation: method can then choose to forward the message to another object. (If that object can’t respond to the message either, it too will be given a chance to forward it.)

The forwardInvocation: message thus allows an object to establish relationships with other objects that will, for certain messages, act on its behalf. The forwarding object is, in a sense, able to “inherit” some of the characteristics of the object it forwards the message to.

当一个对象被发送一个没有相应方法的消息时,运行时系统给接收对象一个委托这消息到另一个接收对象的机会。它通过创建1个NSInvocation对象表示这个消息和发送给接收对象1个包含这NSInvocation对象作为参数的forwardInvocation:消息来委托这个消息。这接收对象的forwardInvocation:方法能选择转发这个消息到另一个对象。(如果那对象也不能响应这个消息,它也将有机会转发它)
这forwardInvocation:消息因此允许1个对象和其它的对某一消息将起作用的对象建立关系。这转发对象在某种意义上能够"继承"转发消息到那个对象上的一些特性。

Important
To respond to methods that your object does not itself recognize, you must override methodSignatureForSelector: in addition to forwardInvocation:. The mechanism for forwarding messages uses information obtained from methodSignatureForSelector: to create the NSInvocation
object to be forwarded. Your overriding method must provide an appropriate method signature for the given selector, either by pre formulating one or by asking another object for one.

为了响应对象本身不能识别的方法,你必须除了forwardInvocation:外还要重写methodSignatureForSelector:。转发消息的原理是用从methodSignatureForSelector:获取的信息去创建一个NSInvocation对象来进行转发。重载的方法必须为被提供的slector提供一个一致的方法签名,或者通过预先制定一个或者通过请求另一个对象。

An implementation of the forwardInvocation: method has two tasks:
· To locate an object that can respond to the message encoded in anInvocation. This object need not be the same for all messages.
· To send the message to that object using anInvocation. ** anInvocation** will hold the result, and the runtime system will extract and deliver this result to the original sender.
In the simple case, in which an object forwards messages to just one destination (such as the hypothetical friend instance variable in the example below), a forwardInvocation: method could be as simple as this:

forwardInvocation:方法的实现有2个任务:

  • 定位一个能响应编码在anInvocation中消息的对象,所有消息的对象不一定相同。
  • anInvocation发送消息给对象。anInvocation将保存这个结果,运行时系统将提取和转发这个结果给原始的发送者。
    在这个简单的情况下,1个对象转发消息只有1个目的地址(像在厦门的例子中假想的friend实例),1个forwardInvocation:方法能是这样简单:

Listing 1

- (void)forwardInvocation:(NSInvocation *)invocation{ 
      SEL aSelector = [invocation selector]; 
      if ([friend respondsToSelector:aSelector])
           [invocation invokeWithTarget:friend];
      else
           [super forwardInvocation:invocation];
}

The message that’s forwarded must have a fixed number of arguments; variable numbers of arguments (in the style of printf()
) are not supported.
The return value of the forwarded message is returned to the original sender. All types of return values can be delivered to the sender: id
types, structures, double-precision floating-point numbers.
Implementations of the forwardInvocation:
method can do more than just forward messages. forwardInvocation:
can, for example, be used to consolidate code that responds to a variety of different messages, thus avoiding the necessity of having to write a separate method for each selector. A forwardInvocation:
method might also involve several other objects in the response to a given message, rather than forward it to just one.
NSObject’s implementation of forwardInvocation:
simply invokes the doesNotRecognizeSelector:
method; it doesn’t forward any messages. Thus, if you choose not to implement forwardInvocation:
, sending unrecognized messages to objects will raise exceptions.

消息转发必须有固定数量的参数,不支持可变数量的参数(像printf()这种格式的)。
转发消息的返回值被原始的发送者返回。所有返回值的类型都能被发送给发送者:id类型,结构体,双精度浮点数。
forwardInvocation:方法的实现能比只转发消息做更多的事情。例如,forwardInvocation:能被用来合并代码来响应多种不同消息,从而避免为每个选择器写一个独立的方法。forwardInvocation方法也能在响应被给的消息时调用几个其它的对象,而不是只转发给1个。
NSObject的forwardInvocation:的实现简单调用doesNotRecognizeSelector:方法,它不转发任何消息。因此,如果你选择不实现forwardInvocation:,发送1个不能识别的消息到对象将抛出异常。

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
Parameters
一个标识返回实现地址方法的选择器。当接收对象是一个实例时,选择器应当标识1个实例方法;当接收对象是一个类时,它应当是个类方法。
Return Value
返回一个包含由给定的选择器标识的方法描述符的NSMethodSignature对象,如果方法不能找到返回nil。

这个方法被用在协议的实现里。这方法也被用在创建1个NSInvocation对象的情况下,比如在转发消息期间。如果你的对象维护一个委托或者是能处理1个没有直接实现的消息,你应该重写这个方法来返回一个一致的方法签名。

+(BOOL)resolveInstanceMethod:(SEL)sel;
Parameters
name
The name of a selector to resolve.
Return Value
Dynamically provides an implementation for a given selector for an instance method.
YES if the method was found and added to the receiver, otherwise NO.
Discussion
This method and resolveClassMethod:
allow you to dynamically provide an implementation for a given selector.
An Objective-C method is simply a C function that take at least two arguments—self and _cmd. Using the class_addMethod
function, you can add a function to a class as a method. Given the following function:
Listing 1

void dynamicMethodIMP(id self, SEL _cmd){
      // implementation ....
}

you can use resolveInstanceMethod: to dynamically add it to a class as a method (called resolveThisMethodDynamically) like this:
Listing 2

+ (BOOL) resolveInstanceMethod:(SEL)aSEL{
     if (aSEL == @selector(resolveThisMethodDynamically)) { 
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:"); 
           return YES; 
      }
       return [super resolveInstanceMethod:aSel];
}

Special Considerations
This method is called before the Objective-C forwarding mechanism is invoked. If respondsToSelector:
or instancesRespondToSelector:
is invoked, the dynamic method resolver is given the opportunity to provide an IMP
for the given selector first.

参考:http://blog.csdn.net/u011774517/article/details/56014855

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,670评论 0 9
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,494评论 18 139
  • 目录 Objective-C Runtime到底是什么 Objective-C的元素认知 Runtime详解 应用...
    Ryan___阅读 1,923评论 1 3
  • 参考链接: http://www.cnblogs.com/ioshe/p/5489086.html 简介 Runt...
    乐乐的简书阅读 2,125评论 0 9
  • 本文转载自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex阅读 735评论 0 1