runtime 使用

本文深入介绍了Objective-C的Runtime机制,包括其概念、作用及常见应用,如动态遍历类成员变量进行字典与模型转换、归档解档操作等,并展示了如何通过Runtime交换方法实现自定义错误处理。
1.什么是runtime?

runtime是一套底层的C语言API,包含很多强大实用的C语言数据类型和C语言函数,平时我们编写的OC代码,底层都是基于runtime实现的。

2.runtime有什么作用?

1.能动态产生一个类,一个成员变量,一个方法
2.能动态修改一个类,一个成员变量,一个方法
3.能动态删除一个类,一个成员变量,一个方法

3.常用的头文件
<code class="objectivec"> <span class="hljs-preprocessor" style="color: rgb(68, 68, 68);">#import <span class="hljs-title"><objc/runtime.h></span> 包含对类、成员变量、属性、方法的操作</span>
 <span class="hljs-preprocessor" style="color: rgb(68, 68, 68);">#import <span class="hljs-title"><objc/message.h></span> 包含消息机制</span></code>
4.常用方法
<code>class_copyIvarList()返回一个指向类的成员变量数组的指针
class_copyPropertyList()返回一个指向类的属性数组的指针</code>

注意:根据Apple官方runtime.h文档所示,上面两个方法返回的指针,在使用完毕之后必须free()。

<code class="sql">ivar_getName()获取成员变量名<span class="hljs-comment" style="color: rgb(136, 0, 0);">-->C类型的字符串</span>
property_getName()获取属性名<span class="hljs-comment" style="color: rgb(136, 0, 0);">-->C类型的字符串</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0);">-------------------------------------</span>
typedef struct objc_method *Method;
class_getInstanceMethod() 
class_getClassMethod()以上两个函数传入返回Method类型
<span class="hljs-comment" style="color: rgb(136, 0, 0);">---------------------------------------------------</span>
method_exchangeImplementations()交换两个方法的实现</code>
5.runtime在开发中的用途

1.动态的遍历一个类的所有成员变量,用于字典转模型,归档解档操作
代码如下:

<code class="objectivec">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)viewDidLoad {    
  [<span class="hljs-keyword" style="color: rgb(0, 0, 136);">super</span> viewDidLoad];    
  <span class="hljs-comment" style="color: rgb(136, 0, 0);">/** 利用runtime遍历一个类的全部成员变量     
      1.导入头文件<objc/runtime.h>     */</span>    
  <span class="hljs-keyword" style="color: rgb(0, 0, 136);">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">int</span> count = <span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>;   
 <span class="hljs-comment" style="color: rgb(136, 0, 0);">/** Ivar:表示成员变量类型 */</span>    
  Ivar *ivars = class_copyIvarList([BDPerson class], &count);<span class="hljs-comment" style="color: rgb(136, 0, 0);">//获得一个指向该类成员变量的指针   </span>
 <span class="hljs-keyword" style="color: rgb(0, 0, 136);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">int</span> i =<span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>; i < count; i ++) {        
<span class="hljs-comment" style="color: rgb(136, 0, 0);">//获得Ivar      </span>
  Ivar ivar = ivars[i];        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//根据ivar获得其成员变量的名称--->C语言的字符串      </span>
  <span class="hljs-keyword" style="color: rgb(0, 0, 136);">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">char</span> *name = ivar_getName(ivar);       
   <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> *key = [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> stringWithUTF8String:name];      
  <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSLog</span>(<span class="hljs-string" style="color: rgb(0, 136, 0);">@"%d----%@"</span>,i,key);
}
}</code>

运行结果如下:


成员变量遍历输出结果.png


获取一个类的全部属性:


获取类的属性的代码实现.png


结果如下:


输出结果.png


应用场景:

  • 可以利用遍历类的属性,来快速的进行归档操作。
  • 将从网络上下载的json数据进行字典转模型。

    <code class="objectivec">注意:归档解档需要遵守<<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSCoding</span>>协议,实现以下两个方法
    - (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">void</span>)encodeWithCoder:(<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSCoder</span> *)encoder{    
        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//归档存储自定义对象    </span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136);">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">int</span> count = <span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>;  
        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//获得指向该类所有属性的指针   </span>
        objc_property_t *properties =     class_copyPropertyList([BDPerson class], &count);   
        <span class="hljs-keyword" style="color: rgb(0, 0, 136);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">int</span> i =<span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>; i < count; i ++) {        
        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//获得        </span>
        objc_property_t property = properties[i];        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//根据objc_property_t获得其属性的名称--->C语言的字符串       </span>
       <span class="hljs-keyword" style="color: rgb(0, 0, 136);">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">char</span> *name = property_getName(property);   
       <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> *key = [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span>   stringWithUTF8String:name];       
       <span class="hljs-comment" style="color: rgb(136, 0, 0);">//      编码每个属性,利用kVC取出每个属性对应的数值            </span>
       [encoder encodeObject:[<span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span> valueForKeyPath:key] forKey:key]; 
     }}
    
    - (instancetype)initWithCoder:(<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSCoder</span> *)decoder{    
          <span class="hljs-comment" style="color: rgb(136, 0, 0);">//归档存储自定义对象    </span>
            <span class="hljs-keyword" style="color: rgb(0, 0, 136);">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">int</span> count = <span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>;   
         <span class="hljs-comment" style="color: rgb(136, 0, 0);">//获得指向该类所有属性的指针   </span>
           objc_property_t *properties = class_copyPropertyList([BDPerson class], &count);   
           <span class="hljs-keyword" style="color: rgb(0, 0, 136);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136);">int</span> i =<span class="hljs-number" style="color: rgb(0, 102, 102);">0</span>; i < count; i ++) {       
           objc_property_t property = properties[i];        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//根据objc_property_t获得其属性的名称--->C语言的字符串       </span>
           <span class="hljs-keyword" style="color: rgb(0, 0, 136);">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">char</span> *name = property_getName(property); 
             <span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> *key = [<span class="hljs-built_in" style="color: rgb(102, 0, 102);">NSString</span> stringWithUTF8String:name];        <span class="hljs-comment" style="color: rgb(136, 0, 0);">//解码每个属性,利用kVC取出每个属性对应的数值      </span>
           [<span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span> setValue:[decoder decodeObjectForKey:key] forKeyPath:key];  
    }   
     <span class="hljs-keyword" style="color: rgb(0, 0, 136);">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136);">self</span>;
    }</code>

    二、交换方法
    通过runtime的method_exchangeImplementations(Method m1, Method m2)方法,可以进行交换方法的实现;一般用自己写的方法(常用在自己写的框架中,添加某些防错措施)来替换系统的方法实现,常用的地方有:

  • 在数组中,越界访问程序会崩,可以用自己的方法添加判断防止程序出现崩溃数组或字典中不能添加nil,如果添加程序会崩,用自己的方法替换系统防止系统崩溃
  • ...
    代码实现如下:

    运行程序崩溃.png

    添加一个分类实现方法交换.png

    再次运行刚才的程序:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值