问题描述
iOS开发中经常要用到模拟器,甚至比真机被用得更频繁。模拟器相对真机有下面几种优势:
* 模拟器一般不卡,性能往往比在真机上跑更稳定,因为电脑有更大的内存,更稳定的网络。
* 可以模拟系统、设备、地理位置等。
* 调IM时,加一个模拟器,就可以互发消息了。
* 导Sandbox数据方便。
* 抓包比真机方便。
* 调试比真机方便,真机需要装证书。
* ...
然而,有时候第三方SDK集成时,第三方SDK可能不提供模拟器的x86架构,那么在链接时,就会提示无法找到符号。
如项目中引入不支持模拟器的SDK,链接时,会报没有找到x86_64架构对应的符号:
如果用lipo -info 命令查看libMyLib.a这个库,就会发现它只提供了 arm7和 arm64两种架构,而没有x86_64架构。
# lipo -info libMyLib.a
Architectures in the fat file: libMyLib.a are: armv7 arm64
如果碰到这种库,引入它之后,项目就不再能在模拟器上运行了,因为它链接都不会过。而我们往往希望引入库之前的其他功能仍能在模拟器上调试。
解决思路
你可以要求SDK厂商提供模拟器的版本,他们顶多改几行脚本,多产生一个x86架构,再把两个.a合并就行。但是如果碰上比较老没有维护的SDK,或者厂商认为SDK不需要考虑模拟器上运行的场景,那就比较麻烦了。
你可以把所有用到SDK的代码通过TARGET_OS_SIMULATOR宏来判断。但是这样可能工作量比较大,而且容易出问题。
这里另外给出一种思路,我们可以根据库中的头文件,自己空实现这些接口,最后编译产生一个x86架构的库,并把它加到工程里面,这样工程链接时就不会出错了。
空实现,指的是函数里什么都不做,直接返回。如:
+ (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action {
return 0;
}
我们知道,objc里面,如果调用空对象的方法,程序并不会有问题,只是什么都不做。如下面代码,虽然footer为nil,仍不会崩溃。
MyRefreshFooter *footer = [MyRefreshFooter footerWithRefreshingTarget:nil refreshingAction:nil];
[footer resetNoMoreData];
所以在模拟器上除了SDK的功能不能用,其他模块的功能并不会受影响。
这种思路除了能解决编译问题,还有种好处是,不用改任何原来工程中的代码,只是附加了一个x86的lib,不影响应用在真机上的功能。
确定了这种思路后,还可以把这种逻辑泛化应用到任意的库中,通过使用适当的工具,可以自动解析objc或cpp的头文件,产生相应空实现的代码,并编译产生需要的x86架构的库。