iOS开发底层之类加载(中) - 13


本章内容描述

  1. 本章的源码依旧是在 objc 源码中。
  2. 类的实现 realizeClassWithoutSwift 重点方法
  3. 运行的主线为: Read_images -》realizeClassWithoutSwift -》 methodizeClass
  4. 懒加载与非懒加载
  5. 分类的创建

一、realizeClassWithoutSwift

  1. 下面源码只显示关键代码 ,一步一步探索类的实现
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

  1. 对象的方法列表进行处理的方法
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.懒加载执行顺序

数据加载推迟到第一次消息的时候

  1. lookUpImpOrForward
  2. realizeClassMayBeSwiftMaybeRelock
  3. realizeClassWithoutSwift
  4. methodizeClass

2. 非懒加载的的执行顺序

map_images的时候回加载所有类的数据

  1. readClass
  2. _getObjc2NonlazyClassList
  3. realizeClassWithoutSwift
  4. methodizeClass

四. category 分类的介绍

  1. 底层也是个结构体
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; 
}
  1. 分类没有元类
  2. 源码路径 : attachToClass -》 attachCategories
  3. 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));
        }
    }
  1. rwe被alloc的时机: 可以搜索整个OBJC 源码工程 ,关键字 extAlloc。 会发现在:动态添加属性, 动态添加方法,添加协议,添加分类的时候才会被创建。

总结

1. ro 、rw 、rwe的区别?

类包含了:元类,父类, flags, method cache ,还有类本身,同时还拥有指向一片干净内存的指针(clean memory), 这就是Ro,加载到内存后,就不能再修改。
相对的,就存在dirty meomory,这就是rw, rw在程序运行时发生更改的内存,但是在实际应用中,类的使用量不多,这样就造成了内存浪费, 所以苹果设计出了 rwe,这样就会把rw中的方法,属性, 协议, 分类等都放入了rwe。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值