IOS 运行时(runtime)机制

1. 概述

OC 是一个全动态语言,OC 的一切都是基于 Runtime 实现的

只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法`

2. 运行时机制

运行时机制是用 C++ 开发的,是一套苹果开源的框架
OC 是基于运行时开发的语言

3. 应用场景

运行时动态获取类的属性

主要应用:

  • 字典转模型框架 MJExtension,JSONModel
  • 利用 关联对象 为分类添加属性
  • 利用 交换方法 拦截系统或其他框架的方法
  • 误区:并不是使用的技术越底层,框架的效率就会越高

导入头文件

#import <objc/runtime.h>

4. 示例

为NSObject添加一个分类

//
//  NSObject+Extension.m
//

#import "NSObject+Extension.h"
#import <objc/runtime.h>

@implementation NSObject (Extension)

const char *propertiesKey = "propertiesKey";
const char *methodsKey = "methodsKey";
const char *protocolKey = "protocolKey";

/// 字典转模型方法
+ (instancetype)objectWithDict:(NSDictionary *)dict
{
    id obj = [[self alloc] init];

    // 获取属性列表
    NSArray *properties = [self propertyList];

    // 遍历属性数组
    for (NSString *key in properties) 
    {
        // 判断字典中是否包含这个key
        if (dict[key] != nil) 
        {
            // 使用 KVC 设置属性值
            [obj setValue:dict[key] forKeyPath:key];
        }
    }

    return obj;
}

/**
 如果能够自动生成这个数组,就好了!
 如果要想动态的获取类的属性,需要使用到“运行时机制”

 class_copyIvarList 成员变量,提示有很多第三方框架会使用 Ivar,能够获得更多的信息
 但是:在 swift 中,由于语法结构的变化,使用 Ivar 非常不稳定,经常会崩溃!
 class_copyPropertyList 属性
 class_copyMethodList 方法
 class_copyProtocolList 协议
 */
/// 返回类的属性列表
+ (NSArray *)propertyList 
{

    // 0. 判断是否存在关联对象, 如果存在, 直接返回
    /** 参数
     1> 关联到得对象
     2> 关联的属性 key
     */
    NSArray *plist = objc_getAssociatedObject(self, propertiesKey);
    if (plist) 
    {
        return plist;
    }

    // 1. 获取 ‘类的属性‘
    /**
     1> 类
     2> 属性的计数指针
     */
    unsigned int count = 0;
    // 返回值是所有属性的数组 obj_property_
    objc_property_t *list = class_copyPropertyList([self class], &count);

    // 创建 存储属性数组
    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];

    for (int i = 0; i < count; ++i) 
    {

        // 获取属性
        objc_property_t pty = list[i];

        // 获取属性名
        const char *cname = property_getName(pty);
        [arrayM addObject:[NSString stringWithUTF8String:cname]];
    }

    // 释放属性数组
    free(list);

    // 设置关联对象
    /**
     1> 关联的对象
     2> 关联对象的 key
     3> 属性数值
     4> 属性的持有方式 reatin, copy, assign
     */
    objc_setAssociatedObject(self, propertiesKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);

    return arrayM.copy;
}

/// 返回类的方法列表
+ (NSArray *)methodList 
{

    // 0. 判断是否存在依赖关系
    NSArray *mlist = objc_getAssociatedObject(self, methodsKey);
    if (mlist) 
    {
        return mlist;
    }

    unsigned int count = 0;
    // 1. 获取方法列表
    Method *list = class_copyMethodList([self class], &count);

    // 存储方法数组
    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];

    for (int i = 0; i < count; ++i) 
    {
        // 获取方法
        Method method = list[i];
        // 获取方法名
        SEL mname = method_getName(method);

        [arrayM addObject: NSStringFromSelector(mname)];
    }

    // 释放数组
    free(list);

    // 设置依赖关系
    objc_setAssociatedObject(self, methodsKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC);

    return arrayM.copy;
}

/// 返回类的实现协议列表
+ (NSArray *)protocolList
{

    // 0. 判断是否存在依赖关系
    NSArray *pList = objc_getAssociatedObject(self, protocolKey);
    if (pList) 
    {
        return pList;
    }

    unsigned int count = 0;
    // 2. 获取协议列表
    Protocol * __unsafe_unretained *list = class_copyProtocolList([self class], &count);

    // 创建协议数组
    NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:count];

    for (int i = 0; i < count; ++i) 
    {

        // 获取协议
        Protocol * __unsafe_unretained prot = list[i];

        const char *pname = protocol_getName(prot);

        [arrayM addObject:[NSString stringWithUTF8String:pname]];
    }

    return arrayM;
}
@end

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。