兼容性适配

iOS代码向下兼容的处理办法

最近项目中在适配 iOS 7 系统,常常遇到unrecognized selector sent to instance的 crash,究其原因,主要是调用了8系统以上才有的方法,如何处理?首先想到的解决办法就是加 if 判断版本,根据版本来执行对应的方法。但是这增加了大量的分散的适配代码,而且也会增加阅读成本,并不是最优解,那么还有没有更好的处理方法呢?

方法调用是通过底层的objc_msgSend(id self, SEL op, ...)来实现的,一个方法==接收者+选择子.

一个完整的消息转发流程是

+(BOOL)resolveInstanceMethod:(SEL)sel ->

-(id)forwardingTargetForSelector:(SEL)aSelector ->

-(void)forwardInvocation:(NSInvocation *)anInvocation

如果仍未找到处理办法,则会抛出unrecognized selector sent to instance的异常。

项目中我们利用resolveInstanceMethod方法,但凡找不到选择子时,系统会在所在类调用所属类的类方法该方法表示能否新增处理这个选择子的判断,返回 bool 值。我们在该方法里动态添加针对 iOS 7的补救方案。主要调用的伪代码如下:

1
2
3
4
5
if ([NSStringFromSelector(sel) isEqualToString:@"XXX"]) {
Method replaceMethod = class_getInstanceMethod([self class], @selector(new XXX));
class_addMethod([self class], sel, method_getImplementation(replaceMethod), method_getTypeEncoding(replaceMethod));
return YES;
}

首先判断该 SEL 是否为你所要处理的 SEL,然后利用 runtime 的 class_addMethod 动态添加一个新方法即可。

这种处理方式相对于根据版本来适配,代码量更少,不分散,便于管理。

待深入研究:iOS 8以上新增了很多 property,我们可以利用 runtime 的 class_addProperty方法来针对7系统单独适配,这样更会一劳永逸解决兼容性问题

显示评论