iOS 类的加载分析 (中)

简介: 我们都知道iOS的整体机制是懒加载, 也是就是使用到, 再去加载, 不使用就释放掉来节省内存.

非懒加载类和懒加载类


总纲领: OC底层探寻

上篇: iOS dyld与objc的关联


我们都知道iOS的整体机制是懒加载, 也是就是使用到, 再去加载, 不使用就释放掉来节省内存.


1. 懒加载类


懒加载类, 他的数据加载是推迟到第一次消息的时候:


数据执行的顺序为 lookUpImpForward -> realizeClassMayBeSwifeMayBeRelock -> realizeClassWithoutSwife -> methodizeClass


2. 非懒加载类


map_images的时候, 加载所有数据. (例如: 可以在类中增加 +load()方法, 来将该类变为非懒加载类, 并且我们知道类中load方法在main函数之前调用)


数据执行的顺序为 _getObjc2NonlazyClassList -> readClass -> realizeClassWithoutSwife -> methodizeClass


_read_images


以下是_read_images部分代码, 具体解析请看代码中注释:


// Category discovery MUST BE Late to avoid potential races  
    // when other threads call the new category code before  
    // this thread finishes its fixups.  
    // +load handled by prepare_load_methods()  
    // Realize non-lazy classes (for +load methods and static instances) -  懒加载类 -> 非懒加载类  
    // 懒 别人不懂我 我就不动 - 让它 提前加载 - load_images 类  
    // 懒加载类在什么时候?   
    for (EACH_HEADER) {  
        classref_t const *classlist =   
            _getObjc2NonlazyClassList(hi, &count);  
        for (i = 0; i < count; i++) {  
            Class cls = remapClass(classlist[i]);  
            const char *mangledName  = cls->mangledName();  
            const char *LGPersonName = "LGPerson";  
           //对研究对象进行过滤 (针对自己写的自定义类进行研究)   
            if (strcmp(mangledName, LGPersonName) == 0) {  
                auto kc_ro = (const class_ro_t *)cls->data();  
                printf("_getObjc2NonlazyClassList: 这个是我要研究的 %s \n",LGPersonName);  
            }  
            if (!cls) continue;  
            addClassTableEntry(cls);  
            if (cls->isSwiftStable()) {  
                if (cls->swiftMetadataInitializer()) {  
                    _objc_fatal("Swift class %s with a metadata initializer "  
                                "is not allowed to be non-lazy",  
                                cls->nameForLogging());  
                }  
                // fixme also disallow relocatable classes  
                // We can't disallow all Swift classes because of  
                // classes like Swift.__EmptyArrayStorage  
            }  // alloc init - 类存在 完备 实例  
            realizeClassWithoutSwift(cls, nil);  
        }  
    }


以下是realizeClassWithoutSwift源码, 具体解析请看代码中注释:


/***********************************************************************  
* realizeClassWithoutSwift  
* Performs first-time initialization on class cls,   
* including allocating its read-write data.  
* Does not perform any Swift-side initialization.  
* Returns the real class structure for the class.   
* Locking: runtimeLock must be write-locked by the caller  
**********************************************************************/  
static Class realizeClassWithoutSwift(Class cls, Class previously)  
{  
    runtimeLock.assertLocked();  
    class_rw_t *rw;  
    Class supercls;  
    Class metacls;  
    const char *mangledName  = cls->mangledName();   
    const char *LGPersonName = "LGPerson";  
   //对研究对象进行过滤 (针对自己写的自定义类进行研究)  
    if (strcmp(mangledName, LGPersonName) == 0) {  
        auto kc_ro = (const class_ro_t *)cls->data();  
        auto kc_isMeta = kc_ro->flags & RO_META;  
        if (!kc_isMeta) {  
            printf("%s: 这个是我要研究的 %s \n",__func__,LGPersonName);  
        }  
    }  
    if (!cls) return nil;  
    if (cls->isRealized()) return cls;  
    ASSERT(cls == remapClass(cls));  
    // fixme verify class is not in an un-dlopened part of the shared cache?  
    / ro (read only)  rw (read write)  rwe (read write ext) rwe只在该类有分类时才有意义
    // data() -> ro  
    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);  
    }  
#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.  
    // cls 信息 -> 父类 -> 元类 : cls LGPerson  
    supercls = realizeClassWithoutSwift(remapClass(cls->superclass), 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->name, "OS_object"))
        {
            // hack for libdispatch et al - isa also acts as vtable pointer  
            hackedDispatch = true;  
            instancesRequireRawIsa = true;  
        }  
        else if (supercls  &&  supercls->superclass  &&  
                 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->superclass = 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源码, 具体解析请看代码中注释:


/***********************************************************************  
* methodizeClass  
* Fixes up cls's method list, protocol list, and property list.  
* Attaches any outstanding categories.  
* Locking: runtimeLock must be held by the caller  
**********************************************************************/  
// realizeClassWithoutSwift 尽管看到了 data() -> ro -> rw (rwe)  
// ro - methodlist - 方法查找的时候 (二分查找) sel 排序  (以下代码为类加载的时候, 就对methedlist进行了排序, 这也就解释了为什么可以用二分查找)
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->mangledName();  
    const char *LGPersonName = "LGPerson";  
    //对研究对象进行过滤 (针对自己写的自定义类进行研究)  
    if (strcmp(mangledName, LGPersonName) == 0) {  
        bool kc_isMeta = cls->isMetaClass();  
        auto kc_rw = cls->data();  
        auto kc_ro = kc_rw->ro();  
        if (!kc_isMeta) {  
            printf("%s: 这个是我要研究的 %s \n",__func__,LGPersonName);  
        }  
    }  
    // 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();  
    // 如果有list, 则对list进行排序
    if (list) {  
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));  
        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  
}

类扩展VS分类


category : 类别, 分类


  1. 专门用来给类添加新的方法
  2. 不能给类添加属性, 添加了成员变量, 也无法取到 (具体要看分类的结构)
  3. 注意: 其实可以通过runtime给分类添加属性
  4. 分类中用@property定义变量, 只会生成getter, setter方法的声明, 不能生成方法实现和带下划线的成员变量.


extension : 类扩展


  1. 可以说是特殊的分类, 也称作匿名分类
  2. 可以给类添加变量属性, 但是是私有变量
  3. 可以给类添加方法, 也是私有方法.




目录
相关文章
|
2月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
221 4
|
2月前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
4月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
57 2
|
1月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
33 8
|
2月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
50 1
|
4月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
168 3
|
3月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。
|
4月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。
|
5月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
【8月更文挑战第20天】在移动应用开发的广阔天地中,Android和iOS两大平台各自占据着重要的位置。本文将深入探讨这两种操作系统的开发环境,从编程语言到开发工具,从用户界面设计到性能优化,以及市场趋势对开发者选择的影响。我们旨在为读者提供一个全面的比较视角,帮助理解不同平台的优势与挑战,并为那些站在选择十字路口的开发者提供有价值的参考信息。
113 17
|
4月前
|
IDE 开发工具 Android开发
安卓与iOS开发环境对比分析
本文将探讨安卓和iOS这两大移动操作系统在开发环境上的差异,从工具、语言、框架到生态系统等多个角度进行比较。我们将深入了解各自的优势和劣势,并尝试为开发者提供一些实用的建议,以帮助他们根据自己的需求选择最适合的开发平台。
59 1