Dive into category

参考链接:http://tech.meituan.com/DiveIntoCategory.html

美团点评的这位同仁对iOS category做了比较深入的研究,如果看懂了这篇文章,相信对category算是比较专业的理解了。这里我来总结几个点吧。

1. category是运行时阶段实现的。跟他做对比的就是extension,extension是编译阶段实现的,extension就是源文件分开写的,跟源文件共同构成类结构,缺少extension可能会造成编译失败。必须要有.m 源文件才能写自己的扩展,比如NSString就不能写extension,只能写category。

2. category运行时的实现,在类加载的时候,会把该类所有category的方法都动态的加到方法列表中,后面编译的.o 会加到列表的前面。类似我们自己实现的runtime增加或者替换新的方法。

3. category的风险,category的方法可以重复的(同一个编译单元不能重复)。所以可能会遇到一个问题,你在一个category写的方法最终没有被调用到,因为其他人在其他模块也写了同样名字的方法,把你写的方法屏蔽了。注意是屏蔽,不是覆盖。还是可以通过runtime方法找到方法列表被屏蔽的方法。这也是很多公司不提倡使用category的主要原因。

4. category不能声明变量。因为是runtime,所以不能改变类的结构,结构在编译阶段就确定了。可以通过以下方法给类增加属性。这一对get/set方法是不是很眼熟,没错,我们给一个控件加个属性有时候就会用这种方法,靠这个方法来传递数据。

objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY);

objc_getAssociatedObject(self,"name")

另外延伸一个链接category的问题。如果自定义类的category单独写在一个文件里,category是不会最后被链接的,因为category是运行时的。这时候需要指定一个link flag

-ObjC

此flag的意思是告诉链接器,如果类有category,记得一起链接进来哦。

但是有个bug,自定义类的category可以链接,但是为框架类或者.a 中的类写的category就不会被链接进来,比如为NSString写一个类别,还是不会被链接。引入另外一个link flag

-all_load 

-force_load

不同处是,force_load需要指定.a的名字。

这样,不管是自定义类的category还是系统类的category,都可以被正确的link进来了,万事大吉!

你可能感兴趣的:(Dive into category)