指针强转到数据结构
realizeClassWithoutSwift
方法里面的auto ro = (const class_ro_t *)cls->data();
,其实就是用到了将指针强转到数据结构。
objc_class 里面
class_rw_t *data() const {
return bits.data();
}
class_data_bits_t 里面
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
attachCategories反推
rwe 何时赋值的?
attachCategories 里面
auto rwe = cls->data()->extAllocIfNeeded();
哪些api调用了attachCategories?
1、attachToClass
调用了 attachCategories
1.1 attachToClass
什么时候调用?
methodizeClass
调用了attachToClass
// Attach categories.
if (previously) {
if (isMeta) {
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_METACLASS);
} else {
// When a class relocates, categories with class methods
// may be registered on the class itself rather than on
// the metaclass. Tell attachToClass to look for those.
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_CLASS_AND_METACLASS);
}
}
objc::unattachedCategories.attachToClass(cls, cls,
isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
attachToClass
的调用取决于previously
,而 previously
的值在methodizeClass(Class cls, Class previously)
赋值,继续往上推导,可以找到 realizeClassWithoutSwift(Class cls, Class previously)
,再继续往上找,可以发现所有的realizeClassWithoutSwift(cls, nil);
调用,传的previously
都是 nil
。
因此只有在objc::unattachedCategories.attachToClass(cls, cls,isMeta ? ATTACH_METACLASS :ATTACH_CLASS);
调用了。
2、load_categories_nolock
调用了 attachCategories
attachList算法
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
uint32_t oldCount = array()->count;
uint32_t newCount = oldCount + addedCount;
array_t *newArray = (array_t *)malloc(array_t::byteSize(newCount));
newArray->count = newCount;
array()->count = newCount;
for (int i = oldCount - 1; i >= 0; i--)
newArray->lists[i + addedCount] = array()->lists[i];
for (unsigned i = 0; i < addedCount; i++)
newArray->lists[i] = addedLists[i];
free(array());
setArray(newArray);
validate();
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];
validate();
}
else {
// 1 list -> many lists
Ptr<List> oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)malloc(array_t::byteSize(newCount)));
array()->count = newCount;
if (oldList) array()->lists[addedCount] = oldList;
for (unsigned i = 0; i < addedCount; i++)
array()->lists[i] = addedLists[i];
validate();
}
}
新添加的list放到newArray的前面,旧的list放到newArray的后面。
分类和主类加载
根据 load
方法是否实现,看看类是如何加载的
1、类和分类都实现load方法
_read_images 懒加载类 - realizeClassWithoutSwift - load_categories_nolock - attachCategories
attachCategories 方法比较耗时。
2、分类实现load,类没有实现
_read_images - realizeClassWithoutSwift - methodizeClass - attachToClass
,没有走 attachCategories
通过data()获取
3、分类没有实现,类实现load方法
_read_images - realizeClassWithoutSwift - methodizeClass - attachToClass
,没有走 attachCategories
通过data()获取
4、分类和类都没有实现load方法
推迟到第一次消息发送的时候 初始化
通过data()获取
5、类和分类都实现load方法,分类有多个,但部分分类没有实现load方法
小结:尽量减少load 方法的使用,否则会比较耗时。
类扩展 VS 分类
简言之,分类可以给类添加方法;扩展类给类添加私有属性和方法。