类和分类的加载
懒加载类和非懒加载类
在 类的加载 篇章里边 我们说了加载了类,分类,协议等等一些事情,注释我们可以看出来这里加载的是非懒加载的类.那么怎么区分懒加载类和非懒加载类呢
- 非懒加载类:实现了
+(void)load()
方法 - 懒加载类 : 没有实现
+(void)load()
方法,并且非懒加载类中没有任何的引用或者使用
比如
//person中为实现+(void)load()方法
@implementation LGPerson
- (void)saySomething{
NSLog(@"%s",__func__);
}
+ (void)sayNB{
NSLog(@"%s",__func__);
}
@end
@interface LGStudent : LGPerson
@property (nonatomic, strong) LGTeacher *teacher;
@end
@implementation LGStudent
static LGTeacher * te;
//teacher为非懒加载
+(void)load
{
NSLog(@"%s",__func__);
}
@end
此时student
和person
都为非懒加载,因为student
继承了person
- 非懒加载类加载
是在read_images时加载的.那么懒加载类呢
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{
//简化后的代码
// 1:第一次进来 - 开始创建表
// gdb_objc_realized_classes : 所有类的表 - 包括实现的和没有实现的
// allocatedClasses: 包含用objc_allocateClassPair分配的所有类(和元类)的表。(已分配)
if (!doneOnce) {
doneOnce = YES;
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
}
// 2:类处理
for (i = 0; i < count; i++) {
Class cls = (Class)classlist[I];
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
}
// 3: 方法编号处理
for (EACH_HEADER) {
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
for (i = 0; i < count; i++) {
const char *name = sel_cname(sels[i]);
sels[i] = sel_registerNameNoLock(name, isBundle);
}
}
// 4: 协议处理
for (EACH_HEADER) {
extern objc_class OBJC_CLASS_$_Protocol;
Class cls = (Class)&OBJC_CLASS_$_Protocol;
NXMapTable *protocol_map = protocols();
protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map,
isPreoptimized, isBundle);
}
}
// 5: 非懒加载类处理
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
addClassTableEntry(cls);
realizeClassWithoutSwift(cls);
}
// 6: 待处理的类
if (resolvedFutureClasses) {
for (i = 0; i < resolvedFutureClassCount; i++) {
Class cls = resolvedFutureClasses[I];
if (cls->isSwiftStable()) {
_objc_fatal("Swift class is not allowed to be future");
}
realizeClassWithoutSwift(cls);
cls->setInstancesRequireRawIsa(false/*inherited*/);
}
free(resolvedFutureClasses);
}
// 7:分类处理
for (EACH_HEADER) {
category_t **catlist =
_getObjc2CategoryList(hi, &count);
bool hasClassProperties = hi->info()->hasCategoryClassProperties();
for (i = 0; i < count; i++) {
category_t *cat = catlist[I];
Class cls = remapClass(cat->cls);
}
}
}
- 懒加载类 和
initialize
方法调用
我们在研究消息发送的时候忽略了一点
IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
bool initialize, bool cache, bool resolver)
{
IMP imp = nil;
bool triedResolver = NO;
runtimeLock.assertUnlocked();
// Optimistic cache lookup
if (cache) {
imp = cache_getImp(cls, sel);
if (imp) return imp;
}
runtimeLock.lock();
checkIsKnownClass(cls);
if (!cls->isRealized()) {
//如果cls未加载调用下边代码
// !!!!!!! 证明懒加载的类是在第一次发送消息的时候加载的
cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
}
//!!!!!!!!! 根据注释我们可以看出来 `initialize `方法也是在第一次发送消息的时候调用的
if (initialize && !cls->isInitialized()) {
runtimeLock.unlock();
_class_initialize (_class_getNonMetaClass(cls, inst));
runtimeLock.lock();
// If sel == initialize, _class_initialize will send +initialize and
// then the messenger will send +initialize again after this
// procedure finishes. Of course, if this is not being called
// from the messenger then it won't happen. 2778172
}
}
分类的加载
1.0 初探 分类的本质
我们利用clang -rewrite-objc xxx.m -o xxx.cpp
进行查看
他是一个结构体.那么我们在源码中搜索
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);
};
1.1 懒加载类 + 懒加载分类
懒加载类是在第一次发消息时加载lookupImpOrForward方法,
lookupImpOrForward--->realizeClassMaybeSwiftAndLeaveLocked--->realizeClassMaybeSwiftMaybeRelock--->realizeClassWithoutSwift---->methodlizeClass。
然后class的data()中就已经存在懒加载的分类方法了。
1. 2非懒加载类 + 非懒加载分类
因为class
为非懒加载,所以首先会加载初始化class;然后因为分类也是非懒加载的,所以会调用_read_images
中的分类相关的加载初始化,在此过程中调用了addUnattachedCategoryForClass
绑定分类到class
的方法:
1.3 非懒加载类 + 懒加载分类
因为class为非懒加载,所以会直接会走正常的class的加载初始化流程:read_images---->realizeClassWithoutSwift---->methodlizeClass。
初始化完成后,class的ro中就已经存在懒加载的分类方法了。这里编译器已经自动的将category方法加进去了;
1.4 懒加载类 + 非懒加载分类
发送消息的时候就去读取 - realizeClassWithoutSwift - methodlizeClass
就是我的类要在消息发送的时候才有 - 但是我的分类提前了 - 需要加载 - read_images - addUnattachedCategoryForClass - 但是没有实现类 就会在下面 prepare_load_methods 实现 prepare_load_methods - realizeClassWithoutSwift 给你提前了实现类的信息 - unattachedCategoriesForClass