一、大纲
1、SIGABRT错误以及出现“unrecognized selector sent to instance XXX”
2、程序中过早释放对象;
3、追到了几个牛逼的函数;
4、启示
二、下面依次说说
1、出现“unrecognized selector sent to instance XXX” 这条错误消息意味着你的app正在试着执行一个不存在的方法。这种情况的发生,主要是都是一个方法被错误的对象调用了(也就是这个对象没有这个方法,但是你调用了他,就错了)。这种错误的解决方法也比较简单,通过使用Exception Breakpoint(异常断点),你可以告诉xcode在一个特定的时候暂停这个程序,这样你就知道是在哪行代码上出现了这个错误,从而继续追踪到出错的对象和出错的selector;
2、这次出现这个SIGABRT错误的原因是我在引用一个第三方库TSTableView的时候没有注意到它在运行中一直需要保留其数据模型TSTableViewModel,而在我的程序中参照案例我只是在TSTableView的初始函数ViewDidLoad中实例化了它,但是并没有保留它,而在之后的操作中,由于还要用到这个Model,所以最后找不到它了,传递给它的selector就回头传递给TSTableView本身,只可惜TSTableView本身并不响应这个selector,最后就报出了"unrecognized selector sent to instance XXX"这样的错误;
3、在追踪的过程中,发现了TSTableView的两个非常厉害的函数:
#pragma mark - Provide TSTableViewDataSource functionality
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if(!signature)
signature = [(id)self.dataSource methodSignatureForSelector:aSelector];
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([self.dataSource respondsToSelector:[anInvocation selector]])
[anInvocation invokeWithTarget:self.dataSource];
else
[super forwardInvocation:anInvocation];
}
这是源代码,具体原理我也没去深究,简单讲一下我的理解,现在的情况是TSTableView本身没有实现一个叫做
TSTableViewDataSource的协议protocol,但是它的一个属性dataSource实现了这个协议,因此,当一个
TSTableViewDataSource协议中定义的selector传递到TSTableView的时候(这里比如说numberOfColumns),TSTableView会先调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector这个方法,判断它自己对这个selector有没有signature,如果没有就返回它的小弟,也就是dataSource属性对于此selector的signature,然后调用下面一个方法
- (void)forwardInvocation:(NSInvocation *)anInvocation,说白了这个方法做的事情也很简单,那就是先判断传递过来的selector自己搞不搞得定,搞得定的话就自己搞定,搞不定的话就让自己的小弟(也就是dataSource属性)出马来搞定。
4、启示
刚开始遇到这个bug的时候自己都有点不知所措,因为我看了一下TSTableView的的确确是不能够响应numberOfColumns这个selector的啊,一时间我都怀疑是不是我下载的第三方库文件有问题,现在终于明白了,selector传递到一个对象的时候,即使表面上看,这个对象是不能响应的,但是这个对象可以通过selector传递的机制,将这个selector传递给其他对象来处理,我想这也是Objective-C语言的动态性的一种真真切切的体现吧。