分类中的方法是通过runtime动态的将分类的方法合并到类对象,元类对象中的。也就是在程序运行过程中合并的,不是编译时合并的。
分类里面的方法一开始(也就是编译完毕的时候)是存在上图这个结构里面。等一下就会利用运行时机制,将这个结构体里面的方法合并到类对象里面去(类方法就合并到元类对象里面去)。
编写一个分类会产生一个struct _category_t对象,在编写另一个分类的话,就会产生另一个新的struct _category_t对象
每一个分类都会生成一个struct _category_t的结构体
上图就是核心方法,static void remethodizeClass(Class cls) 重新组织cls的方法(cls可能是类对象,也可能是元类对象)----也就是类对象的对象方法列表(元类对象的类方法列表)可能重新组织下,可能往里面加东西。
attachCategories(cls,cats)--(attach附加的意思)这个方法的意思就是把分类的信息附加到类对象里面去
memmove --内存移动 memcpy -- 内存拷贝
rw ->methods --原来类的方法列表(图中其箭头所指的方向是其里面的数据,也就是具体方法)
这样过后,分类里面的方法就合并到对应类的方法列表中去了。
过程就是:首先通过传进来的方法列表大小,将类的方法列表扩容,并把类原来的方法列表挪到最后面去,再把传进来的方法列表加进去。
如果一个类的两个分类中,都有同一个方法。那么调用该方法时,哪个分类后被编译就先调用哪个分类的里面的方法。(调用一个对象A方法时,通过isa去类的对象方法列表中查找相应的A方法,找到A方法后,立马返回,就不会再去找了。所以分类的方法覆盖是假的覆盖,原来的方法还是在的,只是排在分类的方法后面了,所以出现假覆盖的现象)。
最后面参与编译的分类优先放到前面,所以优先调用最后参与编译的分类的里面的方法。
上图中先编译分类eat,在编译mjperson,最后编译test。
上图中,类扩展中的属性,方法,一编译的时候就已经存在于我们的类对象中,跟分类是不一样的。
分类的本质:编译完毕的时候,分类都是独立存在的,大家都是那个结构体,但是程序一旦运行的话,运行时机制就会将每一个独立的分类的所有数据先合并到一起,在插入到类原来数据的前面。
网友评论