iOS原理分析之从源码看load与initialize方法(二)

简介: iOS原理分析之从源码看load与initialize方法

四、initialize方法分析


   我们可以采用和分析load方法时一样的策略来对initialize方法的执行情况,进行测试,首先将测试工程中所有类中添加initialize方法的实现。此时如果直接运行工程,你会发现控制台没有任何输出,这是由于只有第一次调用类的方法时,才会执行initialize方法,在main函数中编写如下测试代码:


int main(int argc, const char * argv[]) {

   @autoreleasepool {

       [MySubObjectOne new];

       [MyObjectOne new];

       [MyObjectTwo new];

       NSLog(@"------------");

       [MySubObjectOne new];

       [MyObjectOne new];

       [MyObjectTwo new];

   }

   return 0;

}

运行代码控制台打印效果如下:


2021-02-18 21:29:55.761897+0800 KCObjc[43834:23521232] initialize-cateOne:MyObjectOne

2021-02-18 21:29:55.762526+0800 KCObjc[43834:23521232] initialize:MySubObjectOne

2021-02-18 21:29:55.762622+0800 KCObjc[43834:23521232] initialize-cate:MyObjectTwo

2021-02-18 21:29:55.762665+0800 KCObjc[43834:23521232] ------------

可以看到,打印数据都出现在分割线前,说明一旦一个类的initialize方法被调用后,后续再向这个类发送消息,也不会在调用initialize方法,还有一点需要注意,需要注意,如果对子类发送消息,父类的initialize会先调用,再调用子类的initialize,同时,分类中如果实现了initialize方法则会覆盖类本身的,并且分类的加载顺序靠后的会覆盖之前的。下面我们就通过源码来分析下initialize方法的这种调用特点。


   首先,在调用类的类方法时,会执行runtime中的class_getClassMethod方法来寻找实现函数,这个方法在源码中的实现如下:


Method class_getClassMethod(Class cls, SEL sel)

{

   if (!cls  ||  !sel) return nil;

   return class_getInstanceMethod(cls->getMeta(), sel);

}

通过源码可以看到,调用一个类的类方法,实际上是调用其元类的示例方法,getMeta函数用来获取类的元类,关于类和元类的相关组织原理,我们这里先不扩展。我们需要关注的是class_getInstanceMethod这个函数,这个函数的实现也非常简单,如下:


Method class_getInstanceMethod(Class cls, SEL sel)

{

   if (!cls  ||  !sel) return nil;


   // 做查询方法列表,尝试方法解析相关工作

   lookUpImpOrForward(nil, sel, cls, LOOKUP_RESOLVER);


   // 从类对象中获取方法

   return _class_getMethod(cls, sel);

}

在class_getInstanceMethod方法的实现中,_class_getMethod是最终获取要调用的方法的函数,在这之前,lookUpImpOrForward函数会做一些前置操作,其中就有initialize函数的调用逻辑,我们去掉无关的逻辑,lookUpImpOrForward中核心的实现如下:


IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)

{

   IMP imp = nil;

   // 核心在于!cls->isInitialized() 如果当前类未初始化过,会执行initializeAndLeaveLocked函数

   if (slowpath((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized())) {

       cls = initializeAndLeaveLocked(cls, inst, runtimeLock);

   }


   return imp;

}

initializeAndLeaveLocked会直接调用initializeAndMaybeRelock函数,如下:


static Class initializeAndLeaveLocked(Class cls, id obj, mutex_t& lock)

{

   return initializeAndMaybeRelock(cls, obj, lock, true);

}

initializeAndMaybeRelock函数中会做类的初始化逻辑,这个过程是线程安全的,其核心相关代码如下:


static Class initializeAndMaybeRelock(Class cls, id inst,

                                     mutex_t& lock, bool leaveLocked)

{

   // 如果已经初始化过,直接返回

   if (cls->isInitialized()) {

       return cls;

   }

   // 找到当前类的非元类

   Class nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);

   // 进行初始化操作

   initializeNonMetaClass(nonmeta);


   return cls;

}

initializeNonMetaClass函数会采用递归的方式沿着继承链向上查询,找到所有未初始化过的父类进行初始化,核心实现简化如下:


void initializeNonMetaClass(Class cls)

{

   Class supercls;

   // 标记是否需要初始化

   bool reallyInitialize = NO;

   // 父类如果存在,并且没有初始化过,则递归进行父类的初始化

   supercls = cls->superclass;

   if (supercls  &&  !supercls->isInitialized()) {

       initializeNonMetaClass(supercls);

   }

 

   SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs;

   {

       // 如果当前不是正在初始化,并且当前类没有初始化过

       if (!cls->isInitialized() && !cls->isInitializing()) {

           // 设置初始化标志,此类标记为初始化过

           cls->setInitializing();

           // 标记需要进行初始化

           reallyInitialize = YES;

       }

   }

   // 是否需要进行初始化

   if (reallyInitialize) {

       @try

       {

           // 调用初始化函数

           callInitialize(cls);

       }

       @catch (...) {

           @throw;

       }

       return;

   }

}

callInitialize函数最终会调用objc_msgSend函数来向类发送initialize初始化消息,如下:


void callInitialize(Class cls)

{

   ((void(*)(Class, SEL))objc_msgSend)(cls, @selector(initialize));

   asm("");

}

需要注意,initialize方法与load方法最大的区别在于其最终是通过objc_msgSend来实现的,每个类如果未初始化过,都会通过objc_msgSend来向类发送一次initialize消息,因此,如果子类没有对initialize实现,按照objc_msgSend的消息机制,其是会沿着继承链一路向上找到父类的实现进行调用的,所有initialize方法并不是只会被调用一次,假如父类中实现了这个方法,并且它有多个未实现此方法的子类,则当每个子类第一次接受消息时,都会调用一遍父类的initialize方法,这点非常重要,在实际开发中一定要牢记。


五、结语


   load和initialize方法是iOS开发中非常简单也也非常常用的两个方法,然而其与普通的方法比起来,还有有一些特殊,通过对源码的解读,我们可以更加深刻的理解这些特殊之处的原因及原理,编程的过程就像修行,知其然也知其所以然,与大家共勉。

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

热门文章

最新文章

  • 1
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 2
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 3
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 4
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 6
    iOS8 中无需开源库的内置功能一览
  • 7
    iOS7应用开发7:自定义视图、手势操作
  • 8
    IOS小工具以及精彩的博客
  • 9
    Facebook SDK(iOS)初学讲解
  • 10
    iOS - Swift NSPoint 位置
  • 1
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    14
  • 2
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    28
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    34
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 5
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 6
    uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
    143
  • 7
    【05】2025年1月首发完整版-篇幅较长-苹果app如何上架到app store完整流程·不借助第三方上架工具的情况下无需花钱但需仔细学习-优雅草央千澈详解关于APP签名以及分发-们最关心的一篇来了-IOS上架app
    235
  • 8
    app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
    90
  • 9
    深入探索iOS开发中的SwiftUI框架
    145
  • 10
    ios样式开关按钮jQuery插件
    60