Runtime - 运行时 理解和应用 字典转模型框架 AFN中的交换方法

本文深入探讨了Objective-C运行时的核心概念与应用技巧,包括字典转模型算法、利用关联对象解耦以及方法交换等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


运行时是一种面向对象的编程语言的运行环境,类似于java的虚拟机;

OC的最主要特点,就在于其程序运行时,以发送消息的方式调用方法;

当我们调用方法时,实际上是通过发送消息的方式在列表中查找方法,

每一个类对象(类本质上也是对象)中都有一个对象方法列表,即对象方法缓存,每一个元类对象中都有一个类方法列表,即类方法缓存;方法列表中,每个方法结构体都记录着方法的名称、方法实现、参数类型;通过selector能找到对应的IMP地址;

运行时在开发中的主要应用场景有:

字典转模型;

给分类增加关联对象,从而在开发框架时解耦;

交换方法,当我们无法修改系统方法或第三方框架时,可利用交换方法先执行自己的方法,在执行系统或第三方框架的方法;

 

字典转模型:

#import "NSObject+Runtime.h"

#import <objc/runtime.h>

 

@implementation NSObject(Runtime)

 

// 所有字典转模型框架,核心算法!

+ (instancetype)z_objWithDict:(NSDictionary*)dict {

    // 实例化对象

    idobject = [[self alloc] init];

   

    // 使用字典,设置对象信息

    // 1> 获得self 的属性列表

    NSArray *proList = [self z_objProperties];

   

    // 2> 遍历字典

   [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {

       

       NSLog(@"key%@ --- value %@", key,obj);

       // 3> 判断 key 是否在 proList

       if ([proList containsObject:key]) {

           // 说明属性存在,可以使用 `KVC` 设置数值

           [object setValue:obj forKey:key];

       }

    }];

   

    return object;

}

 

const char *kPropertiesListKey = "ZPropertiesListKey";

 

+ (NSArray *)z_objProperties {

   

    // --- 1. `关联对象`中获取对象属性,如果有,直接返回!

    /**

     获取关联对象 - 动态添加的属性

    

     参数:

     1.对象 self

     2.动态属性的 key

    

     返回值

     动态添加的`属性值`

     */

    NSArray *ptyList = objc_getAssociatedObject(self, kPropertiesListKey);

    if(ptyList != nil) {

       return ptyList;

    }

   

    // 调用运行时方法,取得类的属性列表

    // Ivar 成员变量

    // Method 方法

    // Property 属性

    // Protocol 协议

    /**

     参数

     1.要获取的类

     2.类属性的个数指针

    

     返回值

     所有属性的`数组`C 语言中,数组的名字,就是指向第一个元素的地址

    

    retain/create/copy 需要 release,最好 option + click

     */

    unsigned int count = 0;

    objc_property_t *proList = class_copyPropertyList([self class], &count);

   

    NSLog(@"属性的数量 %d", count);

    // 创建数组

    NSMutableArray *arrayM = [NSMutableArray array];

   

    // 遍历所有的属性

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

       

       // 1. 从数组中取得属性

       /**

        C 语言的结构体指针,通常不需要 `*`

        */

       objc_property_t pty = proList[i];

       

       // 2. pty 中获得属性的名称

       const char *cName = property_getName(pty);

       

       NSString *name = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];

       

//       NSLog(@"%@", name);

       // 3. 属性名称添加到数组

       [arrayM addObject:name];

    }

   

    // 释放数组

    free(proList);

   

    // --- 2. 到此为止,对象的属性数组已经获取完毕,利用关联对象,动态添加属性

    /**

     参数

    

     1.对象 self [OC class 也是一个特殊的对象]

     2.动态添加属性的 key,获取值的时候使用

     3.动态添加的属性值

     4.对象的引用关系

     */

    objc_setAssociatedObject(self, kPropertiesListKey, arrayM.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

   

    return arrayM.copy;

}

 

@end

基本思路:通过运行时方法获取类的属性列表,遍历列表获取属性,遍历字典对属性进行复制,这是第三方字典转模型框架的核型思路;

为了避免每次字典转模型都获取类的属性,运用关联对象,动态添加属性,下次判断关联对象动态添加的属性部位空时,直接return;

 

 

 

AFN中就用到了交换方法:

在AFURLSessionManager.m中

static inline voidaf_swizzleSelector(Class theClass, SEL originalSelector, SELswizzledSelector) {

    Method originalMethod =class_getInstanceMethod(theClass, originalSelector);

    Method swizzledMethod =class_getInstanceMethod(theClass, swizzledSelector);

    method_exchangeImplementations(originalMethod,swizzledMethod);

}

+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass{

    Method afResumeMethod =class_getInstanceMethod(self, @selector(af_resume));

    Method afSuspendMethod =class_getInstanceMethod(self, @selector(af_suspend));

 

    if(af_addMethod(theClass, @selector(af_resume),afResumeMethod)) {

        af_swizzleSelector(theClass, @selector(resume),@selector(af_resume));

    }

 

    if(af_addMethod(theClass, @selector(af_suspend),afSuspendMethod)) {

        af_swizzleSelector(theClass, @selector(suspend),@selector(af_suspend));

    }

}

- (void)af_resume{

    NSAssert([selfrespondsToSelector:@selector(state)], @"Does notrespond to state");

    NSURLSessionTaskState state = [self state];

    [self af_resume];

   

    if (state !=NSURLSessionTaskStateRunning) {

        [[NSNotificationCenter defaultCenter]postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];

    }

}

 

- (void)af_suspend{

    NSAssert([selfrespondsToSelector:@selector(state)], @"Does notrespond to state");

    NSURLSessionTaskState state = [self state];

    [self af_suspend];

   

    if (state !=NSURLSessionTaskStateSuspended) {

        [[NSNotificationCenter defaultCenter]postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];

    }

}

 

通过交换方法resume为自定义的af_resume,在af_resume中再调用resume,同时发出通知,实现了对resume的监听;

内容概要:文章详细介绍了电梯门禁(梯控)系统的硬件安装与接线要点。首先强调了梯控板与楼层按键对接的重要性,包括遵循一一对应原则以避免错层、越层问题,允许空层存在以适应实际需求。接着阐述了不同接线方式(COM、NO、NC端口的不同组合)对用户权限的影响,如单层权限用户刷卡直达指定楼层,多层权限用户在特定接线方式下的操作限制。硬件安装方面,强调了无源干触点设计原则以确保电气隔离,防止系统间干扰,以及读卡器接入的规范要求。文章还介绍了梯控系统的技术原理,如身份验证机制(二维码/IC卡/人脸识别)、消防联动功能(紧急情况下释放所有楼层权限),并指出该系统适用于小区、写字楼等场景,支持机器人乘梯SDK扩展。最后,根据不同场景需求提出了适用的接线方式选择,如严格管控场景下选择4.3接线以实现精准权限控制,限制多层用户手动选层场景下选择4.1接线并配合软件权限设置。; 适合人群:从事电梯安装维护的技术人员、楼宇自动化工程师及相关领域的管理人员。; 使用场景及目标:①指导技术人员正确安装接线梯控系统,确保系统安全稳定运行;②帮助管理人员了解不同接线方式对用户权限的影响,以便根据实际需求选择合适的配置方案;③提升楼宇安全管理服务质量,特别是在小区、写字楼等场所的应用。; 其他说明:梯控系统的正确安装接线不仅关系到系统的正常运作,更直接影响到用户的安全使用体验。因此,在实际操作中务必严格按照规范执行,同关注最新的技术发展应用场景变化,以确保系统始终处于最佳状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值