iOS静态库中慎重使用Category扩展方法(selector not recongized)

转载 2018年04月17日 10:13:05

事情背景

这个坑是前几天踩的,踩的还特别是时候项目马上要发版了,发给测试做最后的验证,测试反馈从log上面看有点诡异,有些手机可以有些手机不可以。因为提测前我是做过自测的,我相信应该没有问题,一同和测试一起继续测试,发现还是有些手机可以有些手机不可以。这么奇怪的问题让我很懵逼呀。按照常理来说应该是要不可以就都不可以呀。因为这是一个请求里面发生的当时我的本能反应是不是网络不稳定呀,但是话又说会来。这如果是网络的问题的话也不会这么巧合呢?好吧 我又回到座位开始吭哧吭哧的查bug了,说好的发完版去健身的,啊啊啊又要泡汤了;因为最近肩膀又开始疼痛了(ps 程序员请保护好自己的身体),今天特意写了一个demo来追踪下原因。(普通的程序员解决问题,优秀的程序员追溯问题的根源,这句话好像哪里有点不太对,开始查找原因吧)。

问题排查

log全开,手机全部部署上看log,刚刚有问题的手机也没有问题呀。我的哥,这什么情况。百思不得其解。然后又用发布demo测试了下,一看好像还真不行。我的天报异常了。

异常

这是什么鬼,我明明写了这个方法呀,为啥会说找不到呢。测试一直问我你是不是给我同样的包呀,为啥之前可以现在不可以。我 我 我开始怀疑人生了。我保证我真的没有改过任何代码除了关闭log。虽然问题找到了但是我还是不知道为啥会这样。想了很久没明白为啥会这样呢。可事实摆在面前呀,就是报异常了。吃完饭回来,突然想到好像有点不一样。之前给测试的包我是直接把sdk的工程直接引入到测试demo的。如下图

直接引用工程项目

我相信很多sdk的开发者测试的时候应该都是这么玩的,因为这样便于调试sdk的问题。可是对外demo里面我引用的是静态.a库。

引用静态库

这是我目前唯一能想到的差别了。一测还真是,只有引入静态库的时候才会出问题,那问题应该是静态库在打包的时候这个方法没有被添加到被扩展的类里面。这个报错的这个方法是很特别的,因为我为了通用所以就使用category特性扩展了NSString。网上一查在静态库中还真有问题,从文章中的原因我们可以看出是:

Unix的标准静态库实现和Objective-C的动态特性之间有一些冲突:Objective-C没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这样当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现"selector not recognized",也就是找不到方法定义的错误。为了解决这个问题,引入了-ObjC标志,它的作用就是将静态库中所有的和对象相关的文件都加载进来

这就是问题的根源。但是另外一篇文章中说在64位的操作体统中链接器有一个bug,会导致只包含有类别的静态库无法使用-ObjC标志来加载文件。变通方法是使用-all_load 或者-force_load标志,它们的作用都是加载静态库中所有文件,不过all_load作用于所有的库,而-force_load后面必须要指定具体的文件。

寻找真凶

对于我上面的描述大家可能会认为问题的根源是我的不同引用方式造成的,直到我刚刚写这个demo之前我也一直这么认为的。但是事实真的是这样吗? NO ,事情的真相是我的开发demo里面增加了-ObjC标志,发布demo里面没有。这才是真正的原因。因为在我刚刚写CategoryExtendDemo的时候我发现不管我是直接引入工程还是引入静态库都会抛出异常。所以说明这两种引用方式没问题。 上面的两篇文章说了是没有增加-ObjC标志的原因。果真我在我的测试demo里面增加这个标志之后两种方式都不会出问题。看来这才是真正的原因。果然我在我的开发demo里面也发现了我确实增加了-ObjC标志。

-ObjC标记

为了进一步测试如果扩展了自定义的类是否也会有同样的问题,我在代码里面测试了一个自定义的类

@interface CustomCategory : NSObject

@end
@implementation CustomCategory

@end

//扩展类
@interface CustomCategory(Extend)

- (void)extendMethod;
@end
@implementation CustomCategory(Extend)

- (void)extendMethod{
    NSLog(@"CustomCategory extendMethod");
}
@end

总结

1、在静态库中如果我们使用了category扩展方法,不管是系统的还是自定义的类如果没有添加-Objc相关标志,都会抛出unrecognized selector sent to instance 异常

2、在测试sdk的时候一定要和发布包操作环境一样,不然真的不知道哪个环节坑了自己,最重要的是还坑了队友。

3、在sdk这种要提供给第三方使用的代码里面减少使用category这种类似黑科技的特性,因为我们不能确保用户会增加-ObjC链接标志,因为如果我们只是在静态库编译的时候加上这个标志,用户没有加上也同样会抛出异常

Demo源码链接

原地址:
链接:https://www.jianshu.com/p/8bbb1c38d3ac

ios framework中使用了 Category 的时候,调用app出现 "selector not recognized"解决方法

framework中使用了 Category 的时候,调用app出现  "selector not recognized" ,解决方法是 在调用的app的 Build Settings --> Lin...
  • canlanyangg
  • canlanyangg
  • 2016-08-25 16:43:20
  • 643

iOS之类别(category)在静态库中不能使用的问题

在静态库封装过程中,如果静态库.a文件包含类别,在主工程将无法使用。 解决方法为:找到主工程的 target --Build Setting--Linking--更改其 Other Linker F...
  • LVXIANGAN
  • LVXIANGAN
  • 2015-05-04 09:01:59
  • 3837

iOS中静态库(static library, .a文件)中的category变得可用

如果在静态库中定义了一个category的话,APP中直接使用的话,会出现"undefined symbols"的错误,明明程序中已经定义了啊,为什么呢?...
  • skylin19840101
  • skylin19840101
  • 2016-07-04 16:53:29
  • 1377

解决ios静态库中的类别(category)在工程中不能使用

解决方法为:找到 target 的图标,更改其 Other Linker Flags 为: -all_load 或 -force_load -force_load,后跟随一个文件位置,可以更精确...
  • yangkunlll
  • yangkunlll
  • 2014-04-24 20:46:37
  • 851

iOS 静态库中使用类别(Category)

如果我们生成一个静态库,库中包含类别的定义以及使用,在使用库的项目中,当用到类别的方法时,程序就会crash,找不到对应的方法实现(环境:xcode6)。 遇到这种问题,解决办法有两个:(1) 一是...
  • skylin19840101
  • skylin19840101
  • 2014-12-07 15:17:10
  • 1064

iOS 静态库里的category中的类方法不能识别问题

最近比较闲,就用Masonry框架对原来项目的布局做了一下调整,然后问题就来了:包含头文件,编写相应代码,build,Success,没问题,Run,运行在模拟器,只要一运行到 - (NSArray ...
  • k00k007
  • k00k007
  • 2016-03-09 09:40:27
  • 307

ios 含category的静态库出现selector not recognized错误的解决办法

Step 1,在每个category头文件(如果没有头文件,则在实现文件)都加上宏定义: #define TT_FIX_CATEGORY_BUG(name) @interfaceTT_FIX_CAT...
  • H_O_W_E
  • H_O_W_E
  • 2014-04-21 12:21:36
  • 1290

[IOS] 引用第三方库 类目(Category)无法加载的问题

这个 bug 在 xcode 4.3 以下会出现,4.3 以后已经修正了。 解决方法为:找到 target 的图标,更改其 Other Linker Flags 为: -all_load 或 -...
  • u012703795
  • u012703795
  • 2014-04-28 15:07:13
  • 1400

iOS 引用外部静态库(.a文件)时,Category方法无法加载问题

苹果的解释为 : http://developer.apple.com/library/mac/#qa/qa1490/_index.html 解决方法为:找到 target 的图标,更改其 Other...
  • u010607889
  • u010607889
  • 2015-08-05 12:59:26
  • 2173

framework中使用了 CateGory 的时候,调用app出现 "selector not recognized"解决方法

framework中使用了 CateGory 的时候,调用app出现  "selector not recognized"
  • tangaowen
  • tangaowen
  • 2014-10-11 16:32:58
  • 2747
收藏助手
不良信息举报
您举报文章:iOS静态库中慎重使用Category扩展方法(selector not recongized)
举报原因:
原因补充:

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