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

Posted iOS_developer_zhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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。

以上是关于iOS开发底层之类加载(中) - 13的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发底层之类加载下 (关联对象) - 14

iOS开发底层之类加载下 (关联对象) - 14

iOS开发底层之类加载上 - 12

iOS底层探索之类的加载: attachCategories分析

iOS底层探索之类的加载: realizeClassWithoutSwift分析

iOS底层探索之类的加载:类的关联对象AssociatedObject