iOS开发底层之类加载(中) - 13
Posted iOS_developer_zhong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发底层之类加载(中) - 13相关的知识,希望对你有一定的参考价值。
文章目录
本章内容描述
- 本章的源码依旧是在 objc 源码中。
- 类的实现 realizeClassWithoutSwift 重点方法
- 运行的主线为: Read_images -》realizeClassWithoutSwift -》 methodizeClass
- 懒加载与非懒加载
- 分类的创建
一、realizeClassWithoutSwift
- 下面源码只显示关键代码 ,一步一步探索类的实现
static Class realizeClassWithoutSwift(Class cls, Class previously)
// 上锁
runtimeLock.assertLocked();
class_rw_t *rw;
Class supercls;
Class metacls;
if (!cls) return nil;
if (cls->isRealized())
validateAlreadyRealizedClass(cls);
return cls;
ASSERT(cls == remapClass(cls));
auto ro = (const class_ro_t *)cls->data(); //只得到地址
auto isMeta = ro->flags & RO_META;
if (ro->flags & RO_FUTURE)
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其实就是ro复制过去的。 所以他们很相似
// ro这里赋值给rw后就不会再动了
rw = objc::zalloc<class_rw_t>();
rw->set_ro(ro);
rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
cls->setData(rw);
// 父类 ,元类的获取
// 类 、 isa的走位图
supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
// 进行赋值
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;
二、methodizeClass
- 对象的方法列表进行处理的方法
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();
// Install methods and properties that the class implements itself.
method_list_t *list = ro->baseMethods();
if (list)
// 1. 对方法列表的处理: 根据内存地址进行排序 具体算法在fixupMethodList方法中
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
// 2. 把方法存放在 rwe 中。
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);
// Attach categories. 分类赋值
if (previously)
if (isMeta)
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_METACLASS);
else
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_CLASS_AND_METACLASS);
objc::unattachedCategories.attachToClass(cls, cls,
#endif
1. 扩展 read_images
- 条件控制进行一次的加载
- 修复预编译阶段的 @selector 的混乱情况
- 错误混乱类的处理
- 修复重映射一些没有被镜像文件加载进来的的类
- 修复一些消息
- 类中有协议的时候, readProtocol
- 修复没有被加载的协议
- 分类处理
- 类的加载处理
- 没有被处理的类,优化被侵犯的类
三、懒加载与非懒加载类的区别
当前类是否实现了load方法,实现了load方法就是非懒加载,反之就是懒加载
1.懒加载执行顺序
数据加载推迟到第一次消息的时候
- lookUpImpOrForward
- realizeClassMayBeSwiftMaybeRelock
- realizeClassWithoutSwift
- methodizeClass
2. 非懒加载的的执行顺序
map_images的时候回加载所有类的数据
- readClass
- _getObjc2NonlazyClassList
- realizeClassWithoutSwift
- methodizeClass
四. category 分类的介绍
- 底层也是个结构体
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;
- 分类没有元类
- 源码路径 : attachToClass -》 attachCategories
- rwe内存分配源码:
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));
- rwe被alloc的时机: 可以搜索整个OBJC 源码工程 ,关键字 extAlloc。 会发现在:动态添加属性, 动态添加方法,添加协议,添加分类的时候才会被创建。
总结
1. ro 、rw 、rwe的区别?
类包含了:元类,父类, flags, method cache ,还有类本身,同时还拥有指向一片干净内存的指针(clean memory), 这就是Ro,加载到内存后,就不能再修改。
相对的,就存在dirty meomory,这就是rw, rw在程序运行时发生更改的内存,但是在实际应用中,类的使用量不多,这样就造成了内存浪费, 所以苹果设计出了 rwe,这样就会把rw中的方法,属性, 协议, 分类等都放入了rwe。
以上是关于iOS开发底层之类加载(中) - 13的主要内容,如果未能解决你的问题,请参考以下文章
iOS底层探索之类的加载: attachCategories分析