Category的原理
- Category編譯之后的底層結(jié)構(gòu)是
struct category_t
悉盆,里面存儲(chǔ)著分類的對(duì)象方法
、類方法
规肴、屬性
、協(xié)議信息
夜畴; - 在程序運(yùn)行的時(shí)候拖刃,
runtime
會(huì)將Category
的數(shù)據(jù),合并到類信息中(類對(duì)象贪绘、元類對(duì)象中)序调。
無論你創(chuàng)建了多少個(gè)分類,分類中有多少對(duì)象方法或類方法,程序運(yùn)行時(shí), 通過runtime動(dòng)態(tài)將分類:
- 對(duì)象方法都統(tǒng)一合并到類中兔簇;
- 類方法都統(tǒng)一合并到元類中发绢。
Category的底層結(jié)構(gòu):
1、當(dāng)程序編譯的時(shí)候垄琐,Category都會(huì)變成如下結(jié)構(gòu)體:
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
- 文件目錄下边酒,終端執(zhí)行
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 輸出的CPP文件
2、源碼
struct category_t {
const char *name;
classref_t cls;
struct method_list_t *instanceMethods;
struct method_list_t *classMethods;
struct protocol_list_t *protocols;
struct property_list_t *instanceProperties;
// Fields below this point are not always present on disk.
struct property_list_t *_classProperties;
method_list_t *methodsForMeta(bool isMeta) {
if (isMeta) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};
Category的加載處理過程:
通過
Runtime
加載某個(gè)類的所有Category
數(shù)據(jù);把所有
Category
的方法
狸窘、屬性
墩朦、協(xié)議數(shù)據(jù)
,合并到一個(gè)大數(shù)組中,(后面參與編譯的Category數(shù)據(jù)翻擒,會(huì)在數(shù)組的前面)氓涣。將合并后的分類數(shù)據(jù)(
方法
牛哺、屬性
、協(xié)議
)劳吠,插入到類原來數(shù)據(jù)的前面引润。
所以,如果Category中重寫了類中的方法痒玩,那該方法的調(diào)用順序 淳附?
- 只調(diào)用分類中重寫了的方法。
- 且眾多分類中蠢古,只會(huì)調(diào)用最后編譯(
編譯順序奴曙,Xcode: Build Phases --> Compile Sources
)的分類中的方法。
原理:
- 方法的實(shí)現(xiàn)是消息發(fā)送機(jī)制草讶,
objc_msgSend([Object Class], @selector(test));
- 以類方法為例洽糟,消息發(fā)送機(jī)制是通過
isa
找到元類對(duì)象
,在元類對(duì)象
的類方法
列表中(包含了分類方法的列表)按順序遍歷查找方法堕战,順序就是:
1.Category數(shù)據(jù)在插到類的前面脊框;
2.Category誰最后編譯,誰在前践啄。
??:分類和類中的+load方法都會(huì)調(diào)用
Category(分類)和Extension(類擴(kuò)展)的區(qū)別:
- 類擴(kuò)展里的內(nèi)容是編譯的時(shí)候浇雹,就已經(jīng)合并到類中去了;
- 而分類里的內(nèi)容是程序運(yùn)行時(shí)屿讽,通過
Runtime
將內(nèi)容合并到類中昭灵。
Category可以添加成員變量嗎 ?
- 不可以伐谈;
- 因?yàn)榉诸惖牡讓咏Y(jié)構(gòu)中烂完,沒有用來存放成員變量的list。
- 如果給分類添加屬性诵棵,只會(huì)生成聲明抠蚣,set和get方法不會(huì)實(shí)現(xiàn)。