卢诗华建筑创新与城市战略 發表於 2022-8-29 08:41:55

iOS开发之Objective-c的Runtime理解指南

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>一、Runtime</li><ul class="second_class_ul"><li>1、概念:</li><li>2、特性:编写的代码具备有运行时、动态特性,从而衍生出 以下4、5</li><li>3、原理:Runtimer在Object-c的使用 程序在三个不同的层次上与运行时系统交互:</li><li>4、作用:</li><li>5、典型事例:</li><li>6、Objc-msgSend所做的事情</li><li>7、消息传递的关键要素</li><li>8、Msg_sender机制:先查询本类是否又该方法的实现---&gt;如果没有逐级找父类,还有一个快速映射表(提高性能)---&gt; 匹配方法 ---&gt; 设置一个执行者---&gt; 消息转发 ---&gt; 没有实现方法</li><ul class="third_class_ul"><li>resolveInstanceMethod</li><li>forwardingTargetForSelector</li><li>methodSignatureForSelector</li><li>forwardInvocation</li></ul></ul><li>二、运行时常用的API:</li><ul class="second_class_ul"><li>objc_*</li><ul class="third_class_ul"></ul><li>class_*</li><ul class="third_class_ul"></ul><li>objcet_*</li><ul class="third_class_ul"></ul><li>method_*</li><ul class="third_class_ul"></ul><li>property_*</li><ul class="third_class_ul"></ul><li>protocol_*</li><ul class="third_class_ul"></ul><li>ivar_*</li><ul class="third_class_ul"></ul><li>sel_*</li><ul class="third_class_ul"></ul><li>imp_*</li><ul class="third_class_ul"></ul></ul></ul></div><p class="maodian"></p><h2>一、Runtime</h2>
<p class="maodian"></p><h3>1、概念:</h3>
<p>概念:Runtime是Objective-c语言动态的核心,即运行时。在面向对象的基础上增加了动态运行,达到很多在编译时确定方法推迟到了运行时,从而达到动态修改、确定、交换。。。属性及方法</p>
<p>作用: 这给程序员写代码带来很大的灵活性,比如说你可以把消息转发给你想要的对象,或者随意交换一个方法的实现之类的!多态 kvo kvc 获得属性方法 添加属性方法</p>
<p>核心: 另外&nbsp;Runtime进行消息解析和转发,动态调用过程!</p>
<p>只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。</p>
<p class="maodian"></p><h3>2、特性:编写的代码具备有运行时、动态特性,从而衍生出 以下4、5</h3>
<p class="maodian"></p><h3>3、原理:Runtimer在Object-c的使用 程序在三个不同的层次上与运行时系统交互:</h3>
<p>(1)通过Object-c源代码进行交互</p>
<p>(2)通过NSObject类中定义的方法交互</p>
<p>(3)通过直接调用运行时函数</p>
<p class="maodian"></p><h3>4、作用:</h3>
<p>(1)在程序运行过程中,动态的创建类,动态添加、修改这个类的属性的方法</p>
<p>(2)遍历一个类中的所有成员变量、属性、以及所有方法</p>
<p>(3)消息传递、转发</p>
<p class="maodian"></p><h3>5、典型事例:</h3>
<p>(1)给系统分类添加属性、方法</p>
<p>(2)方法交换</p>
<p>(3)获取对象的属性、私有属性</p>
<p>(4)字典转换模型</p>
<p>(5)KVO、KVC</p>
<p>(6)(NSClassFromString class)字符串</p>
<p>(7)block</p>
<p>(8)类的自我检测</p>
<p class="maodian"></p><h3>6、Objc-msgSend所做的事情</h3>
<p>(1)找到方法的实现,由于通过单独的类以不同方式创建相同的方法,因此这个方法的实现的确定取决于接收消息的类的对象,也既是说多个实例类对戏那个可以创建同样的方法,每个实例对象中该方法都是独立存在的</p>
<p>(2)调用该方法实现,将接收消息类指针,以及该方法的参数传递给这个类</p>
<p>(3)最后将过程的返回值作为自己的返回值传递</p>
<p class="maodian"></p><h3>7、消息传递的关键要素</h3>
<p>(1)指向superclass指针</p>
<p>(2)会有一个SEL跟方法实现的</p>
<p class="maodian"></p><h3>8、Msg_sender机制:先查询本类是否又该方法的实现---&gt;如果没有逐级找父类,还有一个快速映射表(提高性能)---&gt; 匹配方法 ---&gt; 设置一个执行者---&gt; 消息转发 ---&gt; 没有实现方法</h3>
<ol><li>re solveInstanceMethod&nbsp;&nbsp;决策实力,动态方法解析</li><li>forwardingTargetForSelector&nbsp;转寄Target&nbsp;,设置一个执行者&nbsp;备用接收者</li><li>MethodSignatureForSelector&nbsp;方法签名,</li><li>forwardInvocation&nbsp;转寄求助,消息重定向</li><li>doesNotRecognizeSelector 没有找到方法 崩溃</li></ol>
<p><img alt="" src="https://img.jbzj.com/file_images/article/202208/202208290833311.png" /></p>
<p>先调用resolveInstanceMethod,如果在这里使用runtime动态添加对应的方法,并且返回YES,消息就找到了响应的对象,并将这个新增的方法添加到类的方法缓存列表 如果上面的方法返回NO的话,对象会调用forwardingTargetForSelector方法,以实现消息的转发,让其他对象来处理这个消息。 如果以上两个方法都没有做处理,那么对象会执行最后一个方法methodSignatureForSelector,提供一个有效的方法签名。若提供了有效的方法签名,程序会通过forwardInvocation方法执行签名。若没有提供方法签名,触发doesNotRecognizeSelector方法,触发崩溃。</p>
<p class="maodian"></p><h4>resolveInstanceMethod</h4>
<p>resolveInstanceMethod是Objective-C语言中一种动态方法解析的接口,是得我们可以在运行时动态的为一个selector提供实现。我们只需要实现 +resolveInstanceMethod和+resolveClassMethod方法,并在其中为指定的selector提供实现即可(通过调用运行时函数class_addMethod来添加)。这两个方法都是NSObject中的类方法,其原型为:</p>
<div class="jb51code"><pre class="brush:java;">+ (BOOL)resolveClassMethod:(SEL)name;
+ (BOOL)resolveInstanceMethod:(SEL)name;</pre></div>
<p>参数那么是需要被动态解析的selector;如果在该函数中为指定的selector提供实现,无论返回YES还是NO,编译运行都是正确的。如果在该函数内并没有真正的为selector提供实现,如果返回YES,运行会crash。其原理很简单,因为当前类既没有为selector提供实现,又没有实现消息转发,自然会crash。</p>
<p class="maodian"></p><h4>forwardingTargetForSelector</h4>
<p>forwardingTargetForSelector是Objective-C语言中消息快速重定向的函数。开发者可以在派生类中对其进行重载,从而将无法处理的selector转发给另一个对象。</p>
<p class="maodian"></p><h4>methodSignatureForSelector</h4>
<p>methodSigntureForSelector的作用在在于为另一个类实现的消息创建一个有效的方法签名。如果没有实现有效的方法签名,程序就会崩溃</p>
<p class="maodian"></p><h4>forwardInvocation</h4>
<p>在返回有效的方法签名的情况下,当前对象则会调用forwardInvocation方法,以完成消息的最终传递。</p>
<p>1、动态解析的一个例子</p>
<p><img alt="" src="https://img.jbzj.com/file_images/article/202208/202208290833312.png" /></p>
<p>2、备用接受者</p>
<p><img alt="" src="https://img.jbzj.com/file_images/article/202208/202208290833313.png" /></p>
<p>3.重签名</p>
<p><img alt="" src="https://img.jbzj.com/file_images/article/202208/202208290833314.png" /></p>
<p class="maodian"></p><h2>二、运行时常用的API:</h2>
<p class="maodian"></p><h3>objc_*</h3>
<p>objc_系列函数关注于宏观使用,如类与协议的空间分配,注册,注销等操作</p>
<div class="jb51code"><pre class="brush:java;">// 1.objc_xxx 系列函数
// 函数名称   函数作用
objc_getClass   获取Class对象
objc_getMetaClass   获取MetaClass对象
objc_allocateClassPair   分配空间,创建类(仅在 创建之后,注册之前 能够添加成员变量)
objc_registerClassPair   注册一个类(注册后方可使用该类创建对象)
objc_disposeClassPair   注销某个类
objc_allocateProtocol   开辟空间创建协议
objc_registerProtocol   注册一个协议
objc_constructInstance   构造一个实例对象(ARC下无效)
objc_destructInstance   析构一个实例对象(ARC下无效)
objc_setAssociatedObject   为实例对象关联对象
objc_getAssociatedObje*ct   获取实例对象的关联对象
objc_removeAssociatedObjects   清空实例对象的所有关联对象</pre></div>
<p class="maodian"></p><h3>class_*</h3>
<p>class_系列函数关注于类的内部,如实例变量,属性,方法,协议等相关问题</p>
<div class="jb51code"><pre class="brush:java;">// 2.class_xxx 系列函数
函数名称   函数作用
class_addIvar   为类添加实例变量
class_addProperty   为类添加属性
class_addMethod   为类添加方法
class_addProtocol   为类遵循协议
class_replaceMethod   替换类某方法的实现
class_getName   获取类名
class_isMetaClass   判断是否为元类
objc_getProtocol   获取某个协议
objc_copyProtocolList   拷贝在运行时中注册过的协议列表
class_getSuperclass   获取某类的父类
class_setSuperclass   设置某类的父类
class_getProperty   获取某类的属性
class_getInstanceVariable   获取实例变量
class_getClassVariable   获取类变量
class_getInstanceMethod   获取实例方法
class_getClassMethod   获取类方法
class_getMethodImplementation   获取方法的实现
class_getInstanceSize   获取类的实例的大小
class_respondsToSelector   判断类是否实现某方法
class_conformsToProtocol   判断类是否遵循某协议
class_createInstance   创建类的实例
class_copyIvarList   拷贝类的实例变量列表
class_copyMethodList   拷贝类的方法列表
class_copyProtocolList   拷贝类遵循的协议列表
class_copyPropertyList   拷贝类的属性列表</pre></div>
<p class="maodian"></p><h3>objcet_*</h3>
<p>objcet_系列函数关注于对象的角度,如实例变量</p>
<div class="jb51code"><pre class="brush:java;">
// 3.object_xxx 系列函数
函数名称   函数作用
object_copy   对象copy(ARC无效)
object_dispose   对象释放(ARC无效)
object_getClassName   获取对象的类名
object_getClass   获取对象的Class
object_setClass   设置对象的Class
object_getIvar   获取对象中实例变量的值
object_setIvar   设置对象中实例变量的值
object_getInstanceVariable   获取对象中实例变量的值 (ARC中无效,使用object_getIvar)
object_setInstanceVariable   设置对象中实例变量的值 (ARC中无效,使用object_setIvar)</pre></div>
<p class="maodian"></p><h3>method_*</h3>
<p>method_系列函数关注于方法内部,如果方法的参数及返回值类型和方法的实现</p>
<div class="jb51code"><pre class="brush:java;">// 4.method_xxx 系列函数
函数名称   函数作用
method_getName   获取方法名
method_getImplementation   获取方法的实现
method_getTypeEncoding   获取方法的类型编码
method_getNumberOfArguments   获取方法的参数个数
method_copyReturnType   拷贝方法的返回类型
method_getReturnType   获取方法的返回类型
method_copyArgumentType   拷贝方法的参数类型
method_getArgumentType   获取方法的参数类型
method_getDescription   获取方法的描述
method_setImplementation   设置方法的实现
method_exchangeImplementations   替换方法的实现</pre></div>
<p class="maodian"></p><h3>property_*</h3>
<p>property_系类函数关注与属性*内部,如属性的特性等</p>
<div class="jb51code"><pre class="brush:java;">
// 5.property_xxx 系列函数
函数名称   函数作用
property_getName   获取属性名
property_getAttributes   获取属性的特性列表
property_copyAttributeList   拷贝属性的特性列表
property_copyAttributeValue   拷贝属性中某特性的值</pre></div>
<p class="maodian"></p><h3>protocol_*</h3>
<div class="jb51code"><pre class="brush:java;">
// 6.protocol_xxx 系列函数
函数名称   函数作用
protocol_conformsToProtocol   判断一个协议是否遵循另一个协议
protocol_isEqual   判断两个协议是否一致
protocol_getName   获取协议名称
protocol_copyPropertyList   拷贝协议的属性列表
protocol_copyProtocolList   拷贝某协议所遵循的协议列表
protocol_copyMethodDescriptionList   拷贝协议的方法列表
protocol_addProtocol   为一个协议遵循另一协议
protocol_addProperty   为协议添加属性
protocol_getProperty   获取协议中的某个属性
protocol_addMethodDescription   为协议添加方法描述
protocol_getMethodDescription   获取协议中某方法的描述</pre></div>
<p class="maodian"></p><h3>ivar_*</h3>
<div class="jb51code"><pre class="brush:java;">// 7.ivar_xxx 系列函数
函数名称   函数作用
ivar_getName   获取Ivar名称
ivar_getTypeEncoding   获取类型编码
ivar_getOffset   获取偏移量</pre></div>
<p class="maodian"></p><h3>sel_*</h3>
<div class="jb51code"><pre class="brush:java;">// 8.sel_xxx 系列函数
函数名称   函数作用
sel_getName   获取名称
sel_getUid   注册方法
sel_registerName   注册方法
sel_isEqual   判断方法是否相等</pre></div>
<p class="maodian"></p><h3>imp_*</h3>
<div class="jb51code"><pre class="brush:java;">// 9.imp_xxx 系列函数
函数名称   函数作用
imp_implementationWithBlock   通过代码块创建IMP
imp_getBlock   获取函数指针中的代码块
imp_removeBlock   移除IMP中的代码块</pre></div>
<p>到此这篇关于iOS开发之Objective-c的Runtime理解指南的文章就介绍到这了,更多相关Objective-c的Runtime理解指南内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Objective-C关键字@property使用原理探究</li><li>Objective-C优雅使用KVO观察属性值变化</li><li>Objective-C&nbsp;const常量的优雅使用方法</li><li>Objective-C之Category实现分类示例详解</li><li>iOS&nbsp;Objective-c实现左右滑动切换页面</li><li>IOS开发Objective-C Runtime使用示例详解</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: iOS开发之Objective-c的Runtime理解指南