使用一个包含category的静态库

原文:http://zhenby.com/blog/2012/08/13/zai-jing-tai-ku-zhong-shi-yong-category/

问题

一个项目中使用了一个包含 category 的静态库,但是此项目在运行过程中,该静态库调用 category 增加的方法处,却报 selector not recognized 异常。

最佳方案:方案四,赶时间的可以直接查看方案四;

方案一

将 category 文件跟静态库一起导入到工程中。

缺点

笨,而且多余,在多个地方中存在同一份文件,可能会带来不一致。

方案二

不使用 category,将 category 中新增加的方法增加一个参数,此参数就是 category 扩展的类的实例,例如要扩展 NSDictionary,要增加一个(NSString *)JSONString 方法,那么将此方法修改成(NSString *)JSONStringWithDict: (NSDictionary *)dict,也可以实现想要的效果。

缺点

如果是自己写的 category ,修改起来还比较简单 ,但是如果是开源项目中包含的 category,改动的工作量会很大;
需要额外的类,而且会导致使用 category 的好处尽失。

问题原因

上面的两个方案是在搞不清楚那个错误产生的原因时使用的两个简单、直接的方法,但是都太麻烦了。苹果官方文档中的这个 Q&A QA1490:Building Objective-C static libraries with categories 已经说明了这个问题产生的原因:

这个异常是因为标准 UNIX 静态库、linker 以及 Objective-C 的动态性三者之间的实现导致的,Objective-C 不会为方法定义 linker symbols,它只会为每一个类定义 linker symbols。如果你使用 category 扩展了一个已经存在的类,那么 linker 不会将已有类的实现跟 category 的实现连接起来,这就导致了调用静态库中 category 中新增加的方法时抛出 selector not recognized 的异常。

方案三

在使用静态库的 target 要将 -ObjC 选项传递给 linker,这个标志将会使得 linker 将静态库中原始类及 category 的类文件都载入!

设置这个 -ObjC 选项的具体步骤

在 Xcode 中,查看使用了静态库的那个 target 的 Building Settings,然后找到 Linking 类别中的 Other Linker Flags 选项,设置其值为 -ObjC ;
不过,设置 -ObjC 选项对于 iOS 程序来说有时是不够的,这是因为 linker 中存在一个 bug,所以还是可能会在 -ObjC 的情况下导致 selector not recognized 的异常,为了避免这个 bug,在 Other Linker Flags 中,我们将其值设置为 -all_load 或者 -force_load 即可,见下图:
设置 -ObjC

-all_load 与 -force_load 说明

  • -all_load :linker 会将所有可见的文件都载入到静态库中
  • -force_load :从 Xcode3.2之后才有的选项,能使得文件的载入更细化,每一个你要载入的文件,都要增加一个 -force_load 选项,并且在 -force_load 后面跟上要导入的文件路径,例如:-force_load ../three20/Build/Products/Release-iphoneos/libThree20.a

缺点

  • 使用 -all_load 会导致很多多余文件的导入,会导致静态库体积变大;
  • 使用 -force_load 会很麻烦,要一个个手动添加。

方案四

facebook 的 three20 框架也遇到了这个问题,他们给出了一个更好的解决方案:

1
2
3
4
5
6
7
8
/**
 * Add this macro before each category implementation, so we don't have to use
 * -all_load or -force_load to load object files from static libraries that only contain
 * categories and no classes.
 * See http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html for more info.
 */
 #define TT_FIX_CATEGORY_BUG(name) @interface TT_FIX_CATEGORY_BUG_##name @end \
                                @implementation TT_FIX_CATEGORY_BUG_##name @end

上面的宏定义在 TTCorePreprocessorMacros.h 文件中,在每个 category 的实现文件开头加上:TT_FIX_CATEGORY_BUG({cateory名字}) ,这样就能避免在 iOS 中使用 -ObjC 的 linker 的 bug,但是记住,还是需要把使用静态库的 Target 中的 Building Setting 的 Other Linker Flags 设置成 -ObjC 。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 这段代码的功能是获取分类列表,并按照 sort 字段升序排序。具体来说,它调用了 `categoryService` 中的 `list` 方法,传入了一个 Lambda 表达式作为参数。这个 Lambda 表达式使用 `Condition.getQueryWrapper` 方法构建了一个查询条件,并使用 `lambda` 方法将该条件转换为一个 Lambda 表达式。 在 Lambda 表达式中,使用 `orderByAsc` 方法指定按照 `Category::getSort` 方法返回的字段升序排序。最终,该方法返回一个 `List<Category>` 类型的结果。 ### 回答2: 这段代码是一个使用lambda表达式进行排序的示例。 首先,这个代码片段使用一个名为`categoryService`的服务对象来调用`list`方法。`list`方法可能是一个用于获取`Category`对象列表的方法。这个方法接受一个参数,该参数是一个类型为`QueryWrapper<Category>`的`Condition.getQueryWrapper(category)`对象。 `Condition.getQueryWrapper(category)`用于创建一个`QueryWrapper`对象,该对象用于在数据库中查询`Category`对象。`getQueryWrapper(category)`可能是一个静态方法,它接受一个`category`对象作为参数,并根据这个对象创建查询条件。 接下来,`getQueryWrapper(category)`方法的返回值被传递给`lambda()`方法。`lambda()`方法返回了一个`QueryWrapper`对象,该对象可以使用lambda表达式来进行排序和其他操作。 在这个例子中,`lambda().orderByAsc(Category::getSort)`表示对`Category`对象的属性`sort`进行升序排序。`orderByAsc`方法是`QueryWrapper`对象的方法之一,它接受一个lambda表达式作为参数,该表达式用于指定排序的属性。 最终,`list`方法返回一个`List<Category>`列表,该列表包含按照指定排序规则排序的`Category`对象。这个列表可以在后续的代码中使用。 ### 回答3: 代码片段展示了一个使用Lambda表达式的方法调用,用于获取一个排序后的Category对象列表。具体解释如下: 1. `Category`是一个类或实体对象,代表某个类别或分类。这个类包括一个属性`sort`,用于表示类别的排序值。 2. `categoryService`是一个服务类或组件,提供对类别对象的管理和操作。它包含一个`list`方法,接受一个`QueryWrapper`作为参数,并返回一个`List<Category>`类型的结果。 3. `Condition.getQueryWrapper(category)`将一个指定的`category`对象转换为一个`QueryWrapper`对象。`QueryWrapper`是MyBatis-Plus库提供的用于构建查询条件的工具类。 4. `.lambda()`是`QueryWrapper`对象的一个方法,用于创建一个Lambda表达式作为查询条件。在这个例子中,Lambda表达式表示按照Category对象的`sort`属性进行排序,使用`orderByAsc`方法指定为升序排序。 5. `categoryService.list(...)`调用了`list`方法,并传入上一步构建好的`QueryWrapper`对象作为参数。该方法返回一个经过排序后的`List<Category>`对象,其中的Category对象按照`sort`属性值从小到大排序。 总的来说,这段代码的功能是通过条件查询方法获取并按照Category对象的`sort`属性进行升序排序的Category对象列表。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值