前言
在上一篇文章iOS底层原理之类的加载原理(上)中我们探索了_objc_init的流程,在_read_images里面知道了非懒加载类初始化方法realizeClassWithoutSwift,下面让我们一起来探索一下:
一、realizeClassWithoutSwift
自己加的这个方法是为了判断当前执行的类是否为要调试的LGPerson,如果不是,直接跳过,如果是再向下执行,
static Class realizeClassWithoutSwift(Class cls, Class previously)
{
runtimeLock.assertLocked();
class_rw_t *rw;
Class supercls;
Class metacls;
if (!cls) return nil;
// 自己加的代码
const char *mangledName = cls->nonlazyMangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
// 普通写得类 他是如何
printf("%s - 要研究的: - %s\n",__func__,mangledName);
}
if (cls->isRealized()) {
validateAlreadyRealizedClass(cls);
return cls;
}
ASSERT(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
// data() - ro -> 开辟rw
// 从mach-o文件中读取数据data,转成class_ro_t的数据结构
// ro是在编译阶段即确定下来的数据结构 clean memory,而rw是运行时的结构 dirty memory ,所以需要开辟rw的数据空间
auto ro = (const class_ro_t *)cls->data();
auto isMeta = ro->flags & RO_META;
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data. ro -> rw
rw = objc::zalloc<class_rw_t>();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
}
// 干净内存地址ro 脏内存地址rw
// 运行时 - 内存 ro - copy - rw 内存操作比较严重
// 并不是每一个类都需要插入,进行修改的很少,(rw扩展会导致内存占用很多,直接复制ro),如果动态性扩展一个rwe
cls->cache.initializeToEmptyOrPreoptimizedInDisguise();
#if FAST_CACHE_META
if (isMeta) cls->cache.setBit(FAST_CACHE_META);
#endif
// Choose an index for this class.
// Sets cls->instancesRequireRawIsa if indexes no more indexes are available
cls->chooseClassArrayIndex();
if (PrintConnecting) {
_objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
cls->nameForLogging(), isMeta ? " (meta)" : "",
(void*)cls, ro, cls->classArrayIndex(),
cls->isSwiftStable() ? "(swift)" : "",
cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
}
// Realize superclass and metaclass, if they aren't already.
// This needs to be done after RW_REALIZED is set above, for root classes.
// This needs to be done after class index is chosen, for root metaclasses.
// This assumes that none of those classes have Swift contents,
// or that Swift's initializers have already been called.
// fixme that assumption will be wrong if we add support
// for ObjC subclasses of Swift classes.
supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
#if SUPPORT_NONPOINTER_ISA
if (isMeta) {
// Metaclasses do not need any features from non pointer ISA
// This allows for a faspath for classes in objc_retain/objc_release.
cls->setInstancesRequireRawIsa();
} else {
// Disable non-pointer isa for some classes and/or platforms.
// Set instancesRequireRawIsa.
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && 0 == strcmp(ro->getName(), "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->getSuperclass() &&
supercls->instancesRequireRawIsa())
{
// This is also propagated by addSubclass()
// but nonpointer isa setup needs it earlier.
// Special case: instancesRequireRawIsa does not propagate
// from root class to root metaclass
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
}
}
// SUPPORT_NONPOINTER_ISA
#endif
// Update superclass and metaclass in case of remapping
cls->setSuperclass(supercls);
cls->initClassIsa(metacls);
// Reconcile instance variable offsets / layout.
// This may reallocate class_ro_t, updating our ro variable.
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// Set fastInstanceSize if it wasn't set already.
cls->setInstanceSize(ro->instanceSize);
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// Propagate the associated objects forbidden flag from ro or from
// the superclass.
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
// Attach categories
methodizeClass(cls, previously);
return cls;
}
1.流程分析
首先进行相关变量的声明,判断类是否已经实现,如果已经实现直接返回。用于递归控制,因为后面的流程中会进行递归实现父类和元类,根类的父类是nil,元类的isa指向自己,所以这样可以保证类只会被初始化一次。
if (!cls) return nil;
if (cls->isRealized()) {
validateAlreadyRealizedClass(cls);
return cls;
}
-
rw初始化。这里涉及到干净内存clean memory和脏内存dirty memory的概念。
-
ro属于clean memory,在编辑时即确定的内存空间,只读,加载后不会发生改变的内存空间,包括类名称、方法、协议和实例变量的信息;
rw的数据空间属于dirty memory,rw是运行时的结构,可读可写,由于其动态性,可以往类中添加属性、方法、协议。在运行时会发生变更的内存。 -
rwe类的额外信息。在WWDC2020中也提到,只有不到10%的类真正的更改了他们的方法,并不是每一个类都需要插入数据,进行修改的类很少,避免资源的消耗,所以就有了rwe。
auto ro = (const class_ro_t *)cls->data();
auto isMeta = ro->flags & RO_META;
// 判断是否为元类
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro();
ASSERT(!isMeta);
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
rw = objc::zalloc<class_rw_t>();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
}
- 实现父类和元类,如果还没有实现的情况下。
这需要在上面设置 RW_REALIZED 之后完成,对于根类。
这需要在选择类索引后完成,对于根元类。
这假设这些类都没有 Swift 内容,或者 Swift 的初始化程序已经被调用。
修正如果我们添加对 Swift 类的 ObjC 子类的支持,假设将是错误的。。
supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
- Isa处理,在前面学习isa的时候,对于NONPOINTER_ISA进行了位域处理,指针优化,Isa的末尾位是1,Isa不单单代表一个指针。而对于元类以及特殊情况下的场景的一些类,无需开启指针优化的类,使用Raw Isa,Isa的末尾位是0。
#if SUPPORT_NONPOINTER_ISA
if (isMeta) {
// Metaclasses do not need any features from non pointer ISA
// This allows for a faspath for classes in objc_retain/objc_release.
cls->setInstancesRequireRawIsa();
} else {
// Disable non-pointer isa for some classes and/or platforms.
// Set instancesRequireRawIsa.
bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
bool rawIsaIsInherited = false;
static bool hackedDispatch = false;
if (DisableNonpointerIsa) {
// Non-pointer isa disabled by environment or app SDK version
instancesRequireRawIsa = true;
}
else if (!hackedDispatch && 0 == strcmp(ro->getName(), "OS_object"))
{
// hack for libdispatch et al - isa also acts as vtable pointer
hackedDispatch = true;
instancesRequireRawIsa = true;
}
else if (supercls && supercls->getSuperclass() &&
supercls->instancesRequireRawIsa())
{
// This is also propagated by addSubclass()
// but nonpointer isa setup needs it earlier.
// Special case: instancesRequireRawIsa does not propagate
// from root class to root metaclass
instancesRequireRawIsa = true;
rawIsaIsInherited = true;
}
if (instancesRequireRawIsa) {
cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
}
}
// SUPPORT_NONPOINTER_ISA
#endif
- 建立子类与父类的双定链表关系,保证子类能找到父类,父类也可以找到子类。初始化类的实例对象的大小,是否有c++析构函数设置,以及关联对象的相关设置。
// Update superclass and metaclass in case of remapping
// 父类、isa关系
cls->setSuperclass(supercls);
cls->initClassIsa(metacls);
// Reconcile instance variable offsets / layout.
// This may reallocate class_ro_t, updating our ro variable.
if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
// Set fastInstanceSize if it wasn't set already.
// 类实例对象的大小设置-在对象初始化的时候会用到
cls->setInstanceSize(ro->instanceSize);
// c++函数
// Copy some flags from ro to rw
if (ro->flags & RO_HAS_CXX_STRUCTORS) {
cls->setHasCxxDtor();
if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
cls->setHasCxxCtor();
}
}
// Propagate the associated objects forbidden flag from ro or from
// the superclass.
if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
(supercls && supercls->forbidsAssociatedObjects()))
{
rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
}
// 建立类 子类的双向链表关系
// Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
- cls->setInstanceSize(ro->instanceSize);
这个地方是不是很熟悉,我们在创建对象的时候,class_createInstanceFromZone流程中,在进行对象大小初始化时,使用到了instanceSize。 - 方法化当前的类,向类中添加方法,协议、属性,同时对方法列表进行排序等操作。
// Attach categories 附加类别 - 方法化当前的类,对类进行扩展
// Attach categories
methodizeClass(cls, previously);
2.流程总结
- 当前cls对象为LGPerson,通过_read_images读取到当前的LGPerson,然后调用realizeClassWithoutSwift设置LGPerson的rw数据
- 当前cls对象为LGPerson,通过realizeClassWithoutSwift方法内的supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);即在此调用此方法设置LGPerson的父类NSObject,但是此时父类NSObject是已经实例话的类即cls->isRealized判断为true,直接return cls,不会再次触发superclass与metaclass
- 当前cls对象为LGPerson,通过realizeClassWithoutSwift方法内的metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);即在此调用此方法设置LGPerson的元类
- 当前cls对象为LGPerson(metaclass),通过realizeClassWithoutSwift方法内的supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);即在此调用此方法设置LGPerson的元类的父类,也就是设置NSObject的元类,即根元类,但是此时是已经实例话的类即cls->isRealized判断为true,直接return cls,不会再次触发superclass与metaclass
- 当前cls对象为LGPerson(metaclass),metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);即在此调用此方法设置LGPerson的元类的根元类,但是此时是已经实例话的类即cls->isRealized判断为true,直接return cls,不会再次触发superclass与metaclass,自此,isa指向关系完成。
二、methodizeClass
- methodizeClass
- 修复cls的方法列表,协议列表和属性列表。
- 附加任何突出类别。
- 锁定:runtimeLock必须由调用者持有
static void methodizeClass(Class cls, Class previously)
{
runtimeLock.assertLocked();
bool isMeta = cls->isMetaClass();
auto rw = cls->data();
auto ro = rw->ro();
auto rwe = rw->ext();
const char *mangledName = cls->nonlazyMangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
// 普通写得类 他是如何
if (!isMeta) {
printf("%s - 要研究的: - %s\n",__func__,mangledName);
}
}
// Methodizing for the first time
if (PrintConnecting) {
_objc_inform("CLASS: methodizing class '%s' %s",
cls->nameForLogging(), isMeta ? "(meta)" : "");
}
// Install methods and properties that the class implements itself.
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
if (rwe) rwe->methods.attachLists(&list, 1);
}
property_list_t *proplist = ro->baseProperties;
if (rwe && proplist) {
rwe->properties.attachLists(&proplist, 1);
}
protocol_list_t *protolist = ro->baseProtocols;
if (rwe && protolist) {
rwe->protocols.attachLists(&protolist, 1);
}
// Root classes get bonus method implementations if they don't have
// them already. These apply before category replacements.
if (cls->isRootMetaclass()) {
// root metaclass
addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
}
// 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);
#if DEBUG
// Debug: sanity-check all SELs; log method list contents
for (const auto& meth : rw->methods()) {
if (PrintConnecting) {
_objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
cls->nameForLogging(), sel_getName(meth.name()));
}
ASSERT(sel_registerName(sel_getName(meth.name())) == meth.name());
}
#endif
}
1.流程分析
- 将方法列表添加到数组中。
重新分配未固定的方法列表。
新方法预先添加到方法列表数组中。
static void
prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
bool baseMethods, bool methodsFromBundle, const char *why)
{
runtimeLock.assertLocked();
if (addedCount == 0) return;
const char *mangledName = cls->nonlazyMangledName();
const char *LGPersonName = "LGPerson";
if (strcmp(mangledName, LGPersonName) == 0) {
printf("111111");
}
// There exist RR/AWZ/Core special cases for some class's base methods.
// But this code should never need to scan base methods for RR/AWZ/Core:
// default RR/AWZ/Core cannot be set before setInitialized().
// Therefore we need not handle any special cases here.
if (baseMethods) {
ASSERT(cls->hasCustomAWZ() && cls->hasCustomRR() && cls->hasCustomCore());
} else if (cls->cache.isConstantOptimizedCache()) {
cls->setDisallowPreoptCachesRecursively(why);
} else if (cls->allowsPreoptInlinedSels()) {
#if CONFIG_USE_PREOPT_CACHES
SEL *sels = (SEL *)objc_opt_offsets[OBJC_OPT_INLINED_METHODS_START];
SEL *sels_end = (SEL *)objc_opt_offsets[OBJC_OPT_INLINED_METHODS_END];
if (method_lists_contains_any(addedLists, addedLists + addedCount, sels, sels_end - sels)) {
cls->setDisallowPreoptInlinedSelsRecursively(why);
}
#endif
}
// Add method lists to array.
// Reallocate un-fixed method lists.
// The new methods are PREPENDED to the method list array.
for (int i = 0; i < addedCount; i++) {
method_list_t *mlist = addedLists[i];
ASSERT(mlist);
// Fixup selectors if necessary
if (!mlist->isFixedUp()) {
fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
}
}
// If the class is initialized, then scan for method implementations
// tracked by the class's flags. If it's not initialized yet,
// then objc_class::setInitialized() will take care of it.
if (cls->isInitialized()) {
objc::AWZScanner::scanAddedMethodLists(cls, addedLists, addedCount);
objc::RRScanner::scanAddedMethodLists(cls, addedLists, addedCount);
objc::CoreScanner::scanAddedMethodLists(cls, addedLists, addedCount);
}
}
- 重新排序方法列表
static void
fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
{
runtimeLock.assertLocked();
ASSERT(!mlist->isFixedUp());
if (!mlist->isUniqued()) {
mutex_locker_t lock(selLock);
for (auto& meth : *mlist) {
const char *name = sel_cname(meth.name());
meth.setName(sel_registerNameNoLock(name, bundleCopy));
}
}
/// 按选择器地址排序。
// 不要尝试对小列表进行排序,因为它们是不可变的。
// 不要尝试对非标准大小的大列表进行排序,如 stable_sort
// 不会正确复制条目。
if (sort && !mlist->isSmallList() && mlist->entsize() == method_t::bigSize) {
method_t::SortBySELAddress sorter;
std::stable_sort(&mlist->begin()->big(), &mlist->end()->big(), sorter);
}
// 将方法列表标记为唯一且已排序。
// 不能标记小列表,因为它们是不可变的。
if (!mlist->isSmallList()) {
mlist->setFixedUp();
}
}
2.验证及结论
根据前后不同的打印 和地址顺序 ,证明排序成功
上面 : cate_instanceMethod1 - 0x100003d4f
上面 : cate_instanceMethod2 - 0x100003d64
上面 : saySomething - 0x100003e05
上面 : say1 - 0x100003e12
上面 : say2 - 0x100003e17
上面 : say3 - 0x100003e1c
上面 : say4 - 0x100003e21
上面 : say5 - 0x100003e26
上面 : say6 - 0x100003e2b
上面 : say7 - 0x100003e30
上面 : lgName - 0x100003e35
上面 : setLgName: - 0x100003e3c
上面 : nickName - 0x100003e47
上面 : setNickName: - 0x100003e50
下面 : cate_instanceMethod1 - 0x100003d4f
下面 : cate_instanceMethod2 - 0x100003d64
下面 : saySomething - 0x100003e05
下面 : say1 - 0x100003e12
下面 : say2 - 0x100003e17
下面 : say3 - 0x100003e1c
下面 : say4 - 0x100003e21
下面 : say5 - 0x100003e26
下面 : say6 - 0x100003e2b
下面 : say7 - 0x100003e30
下面 : lgName - 0x100003e35
下面 : setLgName: - 0x100003e3c
下面 : nickName - 0x7fff7bf64d49
下面 : setNickName: - 0x7fff7bf64d52
结论:
- 方法的顺序发生了改变。输出sel的地址,发现他们是按照线性递增排列的,这也就验证了,在慢速查找中,可以进行方法列表二分查找算法的原因。二分查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
三、懒加载类与非懒加载类
1.懒加载类
数据加载推迟到第一次发送消息
lookUpImpForward ->realizeClassMaybeSwiftMaybeRelock->realizeClassWithoutSwift->methodizeClass
2.非懒加载类
map_images的时候加载所有数据
_getObjc2NonlazyClassList ->realizeClassMaybeSwiftMaybeRelock->realizeClassWithoutSwift->methodizeClass
三、分类的本质探索
在上面我们提到了methodizeClass是对分类的操作,现在让我们去看看里面做了什么,首先创建LGPerson的分类
@interface LGPerson (LG) <NSObject>
@property (nonatomic, copy) NSString *cate_name;
@property (nonatomic, assign) int cate_age;
- (void)cate_instanceMethod1;
- (void)cate_instanceMethod2;
+ (void)cate_classMethod3;
@end
@implementation LGPerson (LG)
- (void)cate_instanceMethod1{
NSLog(@"%s",__func__);
}
- (void)cate_instanceMethod2{
NSLog(@"%s",__func__);
}
+ (void)cate_classMethod3{
NSLog(@"%s",__func__);
}
@end
将main.m转化成c++文件,发现了这个,LGPerson的分类
static struct _category_t *L_OBJC_LABEL_CATEGORY_$ [1] __attribute__((used, section ("__DATA, __objc_catlist,regular,no_dead_strip")))= {
&_OBJC_$_CATEGORY_LGPerson_$_LG,
};
看一下这个_category_t
struct category_t {
const char *name;
classref_t cls;
WrappedPtr<method_list_t, PtrauthStrip> instanceMethods;
WrappedPtr<method_list_t, PtrauthStrip> 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);
protocol_list_t *protocolsForMeta(bool isMeta) {
if (isMeta) return nullptr;
else return protocols;
}
};
有点疑惑,回头看一下methodizeClass,发现里面有这样一段代码
// 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);
}
}
进入到attachToClass
class UnattachedCategories : public ExplicitInitDenseMap<Class, category_list>
{
public:
void addForClass(locstamped_category_t lc, Class cls)
{
runtimeLock.assertLocked();
if (slowpath(PrintConnecting)) {
_objc_inform("CLASS: found category %c%s(%s)",
cls->isMetaClassMaybeUnrealized() ? '+' : '-',
cls->nameForLogging(), lc.cat->name);
}
auto result = get().try_emplace(cls, lc);
if (!result.second) {
result.first->second.append(lc);
}
}
void attachToClass(Class cls, Class previously, int flags)
{
runtimeLock.assertLocked();
ASSERT((flags & ATTACH_CLASS) ||
(flags & ATTACH_METACLASS) ||
(flags & ATTACH_CLASS_AND_METACLASS));
auto &map = get();
auto it = map.find(previously);
if (it != map.end()) {
category_list &list = it->second;
if (flags & ATTACH_CLASS_AND_METACLASS) {
int otherFlags = flags & ~ATTACH_CLASS_AND_METACLASS;
attachCategories(cls, list.array(), list.count(), otherFlags | ATTACH_CLASS);
attachCategories(cls->ISA(), list.array(), list.count(), otherFlags | ATTACH_METACLASS);
} else {
attachCategories(cls, list.array(), list.count(), flags);
}
map.erase(it);
}
}
void eraseCategoryForClass(category_t *cat, Class cls)
{
runtimeLock.assertLocked();
auto &map = get();
auto it = map.find(cls);
if (it != map.end()) {
category_list &list = it->second;
list.erase(cat);
if (list.count() == 0) {
map.erase(it);
}
}
}
void eraseClass(Class cls)
{
runtimeLock.assertLocked();
get().erase(cls);
}
};
可以看出这里做了一些方法的处理,那么它又是怎么控制的呢,我们继分析,
我们先看下rwe,auto methodizeClass这个函数由这行代码rwe = rw->ext();为rwe控制,我们看下:
class_rw_ext_t *ext() const {
return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext);
}
class_rw_ext_t *extAllocIfNeeded() {
auto v = get_ro_or_rwe();
if (fastpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext);
} else {
return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext));
}
}
从上图可以看出extAllocIfNeeded可以条件判断,我们搜下
extAllocIfNeeded,得到如下:
attachCategories在这个函数中找到了调用,在添加分类的时候rwe就是能够赋上值的。
addMethods_finish添加方法的时候也会赋值。
class_addProtocol添加协议的时候也会赋值。
_class_addProperty添加属性的时候也会赋值。
objc_duplicateClass重命名的时候也会赋值。
也就是说动态处理时候才会对rwe的处理。
我们重点关注attachCategories分类的加载。
我们搜索attachCategories
attachToClass有调用。
load_categories_nolock有调用。
总结
本次我们介绍了realizeClassWithoutSwift、methodizeClass、分类的本质探索、简单提到了懒加载类与非懒加载类,先告一段落,将在下一篇文章中讲述非懒加载类和非懒加载分类、attachCategories的详解,谢谢
本文详细剖析了iOS中非懒加载类realizeClassWithoutSwift的执行流程,涉及类的初始化、父类和元类的递归实现、方法列表的排序与分类处理,以及lazy加载与非lazy加载的区别。
3万+

被折叠的 条评论
为什么被折叠?



