利用objc的runtime来定位次线程中unrecognized selector sent to instance的问题

原创 2014年06月17日 15:32:16

昨天遇到一个只有一行错误信息的问题:

-[NSNull objectForKey:]: unrecognized selector sent to instance 0x537e068

由于这个问题发生在次线程,所以没有太有用的堆栈信息,而是只有简单的SIGABRT信息:



考虑到unrecognized selector sent to instance这类问题是由于向某个对象发送了未实现的消息,这个过程大致如下(图片摘自这里):


参考Objective-C的对象模型:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

消息发送的流程大致如下:

  • 判断发送的消息是否为retain等内存管理方法;
  • 判断receiver是否为nil;
  • 判断是否在方法缓存中,即struct objc_cache *cache;
  • 判断是否在方法列表中,即struct objc_method_list **methodLists,由于对象的方法可以动态添加,所以这里的类型是struct objc_method_list **,可以参考objc-class.m源文件;
  • 判断是否在继承体系中——到这里,称之为Messaging过程。
  • 如果实在找不到,就执行Dynamic Method Resolution过程,即尝试调用resolveInstanceMethod:或resolveClassMethod:方法,我们可以通过实现这两个方法来动态添加方法;
  • 动态方法解析过程如果返回NO,那么还有最后的拯救机会,就是Message Forwarding消息转发过程(参考NSObject.h):

- (id)forwardingTargetForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

我第一反应是添加resolveInstanceMethod:来观察,这是一个类方法,所以得添加到metaClass上:

Class metaClass = objc_getMetaClass("NSNull");
SEL sel = @selector(resolveInstanceMethod:);
const char *type = "c@::";
class_addMethod(metaClass, sel, (IMP)resolveInstanceMethod, type);

但遗憾的是,即便此时方法寻找不到时会调用到resolveInstanceMethod:方法,不过在设置的断点位置看也已经没有明确的堆栈信息了,所以我就直接添加找不到的方法objectForKey:来定位:

Class metaClass = objc_getMetaClass("NSNull");
SEL sel = @selector(objectForKey:);
const char *type = "@@:@";
class_addMethod(metaClass, sel, (IMP)objectForKey, type);

样一来,通过在我们添加的objectForKey方法中设置断点就可以获取到详细堆栈信息,从而进一步定位到问题所在:
{
  fromId = "\U6d4b\U8bd520#\U65fa\U4f01\U65e0\U7ebf\U6d4b\U8bd5";
  msgContent = "<null>";
  msgSendTime = 1402909302;
  msgType = 12;
  uuid = 0;
}

原因是由于服务端推送的消息中一个必填字段为空,而客户端也刚好在此处没有使用项目代码中约定的类型检查宏(此处应为VFDict),而是直接当做NSDictionary来操作。

iOS -[__NSArrayI addObject:]: unrecognized selector sent to instance~解决方法

//联系人:石虎  QQ: 1224614774昵称:嗡嘛呢叭咪哄 报错: 一 '*** -[__NSArrayM objectAtIndex:]:...
  • shihuboke
  • shihuboke
  • 2017年08月10日 07:17
  • 1021

unrecognized selector sent to instance问题原因之一及解决方法。

1. 自己遇到的问题: 2015-05-28 15:46:53.046 test[5298:146142] *** Terminating app due to uncaught exception...
  • yishengzhiai005
  • yishengzhiai005
  • 2015年05月28日 16:20
  • 14229

unrecognized selector sent to class

问题:Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[UIBarButtonIte...
  • ugg
  • ugg
  • 2012年01月31日 10:15
  • 24142

unrecognized selector sent to instance 0x266070

unrecognized selector sent to instance 字面上翻译:给实体对象发送了不认识的消息。 遇到这个问题: 大概有如下两个原因: 1.对象过早的释放掉了,你引...
  • jiajiayouba
  • jiajiayouba
  • 2014年04月14日 23:33
  • 27235

unrecognized selector sent to instance出现的原因和解决方案

概述:造成unrecognized selector sent to instance iphone,大部分情况下是因为对象被提前release了,在你心里不希望他release的情况下,指针还在,对...
  • linda_Ly
  • linda_Ly
  • 2014年11月05日 19:57
  • 357

IOS TableView 报异常,unrecognized selector sent to instance(个人)

2013-10-17 17:05:06.471 EWarn_iphone[5384:11303] -[UIView tableView:numberOfRowsInSection:]: unreco...
  • ten11
  • ten11
  • 2013年10月17日 17:16
  • 3145

使用Masonry报unrecognized selector sent to instance的错

问题的来源:       现在我公司有两个项目,A项目(使用xcode的版本比较旧),B项目(使用最新的xcode版本);       B项目是使用cocoaPods管理第三方库,并加了一些第三方...
  • yq910902
  • yq910902
  • 2016年04月13日 19:44
  • 2695

-[XXXX encodeWithCoder:]: unrecognized selector sent to instance 0x12d931d10

2016-12-28 17:03:41.756 eVision论坛[9395:4643589] *** Terminating app due to uncaught exception 'NSInv...
  • sinat_15597209
  • sinat_15597209
  • 2016年12月28日 17:55
  • 1378

iOS 【错误:unrecognized selector sent to instance 0x7aa552b0】

翻译:给实体对象发送了不认识的消息 大概有如下两个出错原因: 1.对象过早的释放掉了,你引用的对象不存在。不能想空对象发送特定的方法(不是全部,因为release等特殊方法,例外)。 2.该...
  • Felicity294250051
  • Felicity294250051
  • 2015年11月13日 16:45
  • 750

错误: [UILabel copyWithZone:]: unrecognized selector sent to instance

12down voteaccepted I guess this was one of those weird bugs with XCode that you can't tr...
  • ganlijianstyle
  • ganlijianstyle
  • 2012年11月16日 07:16
  • 8327
收藏助手
不良信息举报
您举报文章:利用objc的runtime来定位次线程中unrecognized selector sent to instance的问题
举报原因:
原因补充:

(最多只允许输入30个字)