使用OC runtime解决第三方库冲突

前几天在iOS app项目中添加了几个第三方库,各有各的用处,因为一些原因,有些库是不开源的。

添加后,发现app编译不通过,错误如下:

从错误描述中都能看出,app在连接过程中,发现了一些重复的符号,即同样的OC类和方法在不同的库中都有实现:liblibPDRCore.a和libsimpleconfiglib.a这两个库有冲突!恰好,这两个库都要用,而且都不开源,仿佛一下子就走进了死胡同,因为没有办法修改这两个库。

网上搜了一下,碰到这种问题的人还真不少,也提出了解决方案:用lipo命令分解其中一个类,删除重复的符号,再用ar命令重新打包成库,我选择修改liblibPDRCore.a这个库:

1.查看包信息:lipo -info liblibPDRCore.a,提示fat file,那么代表这个包是支持多平台的,例如armv7,armv64等

2.取出armv7包:lipo liblibPDRCore.a -thin armv7 -output armv7/liblibPDRCore_armv7.a

3.解压出object file(.o文件):cd armv7&ar xv liblibPDRCore_armv7.a

4.根据出错信息删除PDRSerAsyncSocket.o:rm PDRSerAsyncSocket.o

5.重新打包:ar rcs liblibPDRCore_armv7.a *.o,记得把旧的库删掉

6.重复1-5把arm64什么的一起改了

7.合并为fat库:lipo -create liblibPDRCore_armv7.a liblibPDRCore_arm64.a -output liblibPDRCore.a

好了,现在用新和成的库替换,并编译,发现编译成功了!

且慢!这和主题OC runtime有什么关系?只是用一些工具去掉了重复符号!

是的,确实没有关系,下面才正式进入主题!

编译是成功了,但实际运行起来呢?非常抱歉,crash了,错误如下:

原因可能是:这两个库虽然有一个名字一样的OC类,有些方法也一样,但并不是完全一样,可以认为,这两个库依赖了另一个开源库,但不是同一个版本,仿佛又走进死胡同鸟!

仔细分析了一些出错信息:liblibPDRCore.a某个地方调用了AsyncSocket类的方法acceptOnAddress:port:error:,但libsimpleconfiglib.a中的AsyncSocket却没有这个方法,造成调用异常。

现在轮到OC runtime上场了,我也只是抱着试一试的态度。前段时间正好看这方面内容,了解到OC可以在运行时动态增加、替换一些类的方法,解决一些实际问题。现在我想到一个思路:用一个空函数,替代AsyncSocket类的方法acceptOnAddress:port:error:,看是否正常运行

1.先获取类类型:Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");

2.给AsyncSocket类添加方法:class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"), IMP, types);,这个函数中,后面两个参数,一个是替换方法,一个是方法参数类型,替换方法参数好搞,直接定义一个C格式的函数,传函数指针即可;方法参数类型怎么弄?

于是,我想到了从libsimpleconfiglib.a库中找一些蛛丝马迹,虽然它和liblibPDRCore.a使用了不同版本的AsyncSocket类,但某些方法应该是类似的,获取可以帮我完成函数class_addMethod所需的最后一个参数

3.用lipo和ar命令获得libsimpleconfiglib.a中的object file:"AsyncSocket.o"

4.查看"AsyncSocket.o"的导出符号:nm AsyncSocket.o,果不其然,发现一个类似的,方法名不同,参数名却一样

5.再看一下liblibPDRCore.a库中的PDRSerAsyncSocket.o的导出符号,确实有"acceptOnAddress:port:error:"这个方法,我们知道,这个目标文件已经被我们去掉了

6.从名称上判断,这两个方法参数一样,而且方法acceptOnInterface确实存在,用method_getTypeEncoding来获取方法的类型即可得到class_addMethod的最后一个参数,用有了这个思路,完成了如下代码:

void impfunc(Class cls, SEL _cmd)
{
    if([NSStringFromSelector(_cmd) isEqualtoString:@"acceptOnAddress"])
    {
        //调用cls的acceptOnInterace的方法
    }
}

- (BOOL)application:...
{
    Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");
    Method _acceptOnInterface = class_getInstanceMethod(_asyncSocketClass,
        NSSelectorFromString(@"acceptOnInterface:port:error:"));
    class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"), 
        (IMP)impfunc, method_getTypeEncoding(_acceptOnInterface));
}

7.编译并运行起来之后,确实走到了impfunc,程序也不崩溃了,但相关的功能不正常,我想还是要真正调用一下acceptOnInterface这个方法才行

8.我想到了解析_cmd的参数,取出参数值,然后再调用objc_msgSend发送消息,尝试了很多方法,没有成功;实际上,我还是走了弯路,各位应该也看出来了,class_addMethod的第三个参数,直接用acceptOnInterface的实现不就行了!method_getImplementation可以帮我们做到,于是代码变成如下,编译后运行,成功了!

- (BOOL)application:...
{
    Class _asyncSocketClass = NSClassFromString(@"AsyncSocket");
    Method _acceptOnInterface = class_getInstanceMethod(_asyncSocketClass,
        NSSelectorFromString(@"acceptOnInterface:port:error:"));
    class_addMethod(_asyncSocketClass, NSSelectorFromString(@"acceptOnAddress:port:error:"), 
        method_getImplementation(_acceptOnInterface ), 
        method_getTypeEncoding(_acceptOnInterface));
}

9.没有了,散会

时间: 2024-10-19 22:00:18

使用OC runtime解决第三方库冲突的相关文章

iOS 第三方库冲突的处理

现象 最近项目组在做一些第三方功能的集成,不止一次的遇到第三方库冲突的问题,报错如下: 1 2 3 4 5 6 duplicate symbol _OBJC_METACLASS_$_JKSerializer in: /Users/tony/Desktop/XXXProject/Lib/libMiPushSDK.a(JSONKit.o) /Users/tony/Library/Developer/Xcode/DerivedData/XXXProject-boqkajmzatzxohbyrrhklf

解决多库冲突的方法

html里写: <p id="p1">我是测试炮灰</p> script里写://解决冲突方法一: jQuery.noConflict(); //此时放弃$,只能用jquery这个关键字代表jquery jQuery(function(){ jQuery('#p').hide();//此时隐藏p标签 }); //解决冲突方法二 var $j = jQuery.noConflict();//用新的符号$j替代旧的$符号 $j(function(){ $j(&quo

认识JQuery,JQuery的优势、语法、多库冲突、JS原生对象和JQuery对象之间相互转换和DOM操作,常用的方法

(一)认识JQuery  JQuery是一个JavaScript库,它通过封装原生的JavaScript函数得到一套定义好的方法    JQuery的主旨:以更少的代码,实现更多的功能 (二)JQuery的优势 1)可以像CSS一样访问和操作DOM 2)修改CSS控制页面外观 3)简化JS代码操作 4)事件代理更加容易 5)动画效果使用方便 6) Ajax技术更加完美 7)大量的基于Jquery的插件 8)可以自定义扩展功能插件 (三)JQuery的语法 格式:$(selector).actio

使用Reveal.app调试整个项目UI时间,增加LD指令 -Objc引起项目中多个静态库冲突问题

今天接触到一个新的UI调试工具教程如下: iOS真机UI调试利器——Reveal 引入增加-ObjC -framework Reveal指令后,发现项目出现多重静态库冲突问题, 首先介绍一个指令: -all_load选项,这会导致所有的类的方法都会被载入,不管“你的程序”有没有用到,所有的,包括系统的,方法会被载入.这个方法不仅会导致你的目标程序大小增大,而且往往容易引起一些冲突,而这些冲突往往你无法解决(常常出现在你链接的各种库中). 可以使用-force_load,这个你可以指定要载入所有方

iOS项目中引用第三方库引发冲突的解决方法

在iOS程序开发过程中,经常会碰见引用第三方库出现类名重复使用,导致冲突. 解决方案 1.使用命令将.a库中的相同的包移除 2.在编译链接项中添加-dead_strip项  补充说明: -dead_strip:删除多余的库符号: -all_load:让链接器把所有找到的目标文件都加载到可执行文件中: -force_load:所做的事情跟-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件的路径 使用命令将.a库中的相同的包移除步骤如下: 1.创建临时文件夹(用

导入第三方库unknown type name &#39;NSString&#39;解决

添加第三方库一般步骤分三步: 1)拖入库文件夹,copy一份加入自己的项目 2)添加库所需要的框架或者动态链接库 3)ARC下修改编译属性 -fno-objc-arc 但是今天加入zipArchive ,按步骤加入,增加libz动态库,修改-fno-objc-arc一下报了23个错误(汗 too many errors emitted, stopping now),都是 expected identifier or '(' ,unknown type name 'NSString',could

Swift: 在Swift中桥接OC文件(自己创建的类文件、第三方库文件)

一.介绍 随着Swift的逐渐成熟,使用swift开发或者混合开发已经成为了一个趋势,本身苹果公司也十分推荐使用Swift这门新语言.目前Swift已经更新到了3.0,估计没有多久4.0就要出来了.那么再用Swift开发时遇到一些问题不可避免,下面就来解决几个常遇到的问题. 二.问题和解决办法 如何在Swift中手动桥接OC? 1.创建swift桥接文件   2.设置桥接文件路径,也即Objective-C Bridging Header的路径,设置完就可以导入自定义的OC类文件使用了 如何使用

iOS开发遇到的坑之六--使用cocopods管理第三方库时,编译出现Library not found for -lPods问题的解决方法

在项目中有时候会遇到Library not found for -lPods(这里的IPods指的是你具体的第三方库)的问题 出现这个错误的原因是:xcode在编译的时候找不到这个库,从而导致项目无法编译! 这里给出几种解决办法: 第一种: a) Search from 'Library' from the Target Settings view and double-click to inspect the value of Library Search Paths b) There are

jQuery与其它库冲突的解决方法(转)

原文出处:http://www.jb51.net/article/24014.htm 在jQuery库中,几乎所有的插件都被限制在它的命名空间里.全局的对象都很好地存储在jQuery命名空间里,因此当把jQuery和其它javascript类库一起使用时,不会引起冲突. (注意:默认情况下,jQuery用$作为自身的缩写而以) 如果jQuery类库和别的类库冲突的话,可以使用jQuerynoConflict()函数来将变量$的控制权移交出给其它的javaScipt库.看下面小片断代码 <scri