iOS |iOS进阶必须掌握的常用的runtime方法

前言

在平日的iOS开发中,最常见的的用到runtime的应该就是分类添加属性了,我们平时在类里使用@property添加属性的时候,系统会自动生成带“”做前缀的的成员变量以及该变量的setter和getter方法。但是在分类里使用@property添加属性,.m文件会出现警告,提示没有实现改属性的的setter和getter方法。需要我们手动添加代码,而且手动添加的代码也无法用“”做前缀+属性变量名去访问属性,需要我们动态用runtime的代码去实现。那么runtime是什么?runtime的方法又有哪些?作为进阶学习,我们应该要掌握哪些常用的runtime代码,接下来一一讲解。

一、什么是runtime

通俗来说,RunTime其实就是一个库,是oc底层的C语言API,我们平时写的oc代码,其实最终都会被编译器转化为runtime代码。

runtime顾名思义就是运行时的意思,即我们使用runtime的代码,系统并不是编译的时候去执行,而是运行中去到该代码处才会去动态执行这些代码。像是一些变量的值,可能根据需求我们得在程序运行到某一个步骤的时候才能确定它的值,然后取出来,这时候则可以使用runtime的代码在对应的那个时刻去获取变量的值,然后动态的做一些操作。

二、runtime的方法

使用RunTime库里的代码,需要引入头文件

#import <objc/runtime.h>

有些函数则需要引入

#import <objc/message.h>

点击进入头文件,可以看到runtime提供的方法

下图只是其中一部分,其他自己可以去头文件自己浏览

image.png

三、runtime需要掌握的方法

为啥我们需要学习runtime?我认为有以下几点

  1.runtime能做一些我们用oc代码比较难实现的功能,例如拦截某个方法,然后进行方法交换(一半是拦截交换系统方法)

  2.我们平时oc的函数调用,实际最后都会变成runtime的消息转发机制,掌握这个消息转发机制,我们就可以把消息重定向到别的对象,从而写出更加灵活的代码,

  3.能利用系统动态调用函数这个机制去动态执行一些操作,比如新增一个对象,添加一个方法or一个属性,替换掉方法等。

runtime有哪些作为进阶需要掌握的方法?

1.给分类添加属性

比如我想给某个SDK里的对象添加属性,但是无法修改这个对象,这时候就可以用分类来实现

这里需要用到关联函数objc_setAssociatedObjectobjc_getAssociatedObject,其定义如下

image.png
函数objc_setAssociatedObject的参数意义如下

第一个参数:表示给哪个对象添加关联

第二个参数:表示关联的key,后面要获取的objc_getAssociatedObject则是通过这个key去获取值

第三个参数:表示这个key对应的值,第四个参数则是这个

第四个参数:policy表示关联策略,是一个枚举,目前有五种策略

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,          
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, 
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   
    OBJC_ASSOCIATION_RETAIN = 01401,     
    OBJC_ASSOCIATION_COPY = 01403          
};

等效于

image.png

而函数objc_getAssociatedObject的参数意义如下

第一个参数:表示关联的对象

第二个参数:表示关联的key,返回值就是上面方法中相同key的value对象

使用方式如下:
先创建一个NSSObjcet的分类
image.pngimage.png

然后为分类添加属性name,然后利用runtime代码设置name的gettersetter方法

NSObject+myobj.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN
@interface NSObject (myobj)
@proprery (nonatomic, strong) NSString *name;
@end
NS_ASSUME_NONNULL_END

NSObject+myobj.m

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



static NSString * const key = @"myName";

@implementation** NSObject (myobj)
- (NSString *)name
{
    return objc_getAssociatedObject(self, &key);
}

- (void)setName:(NSString *)name
{
    objc_setAssociatedObject(self, &key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

这样,就能给生成的NSObject实例添加名字和读取名字了

NSObject *objc = [[NSObject alloc] init];
objc.name = @"hello world";
NSLog(@"%@",objc.name);

2.交换方法

假如我想打印一下用户的app使用路径,我想每个VC的appear和disappear相关函数调用时都打印一下,那么就可以拦截系统的这些方法,然后用我写好的方法进行交换实现

这里需要用到

获取方法函数class_getInstanceMethod

交换函数method_exchangeImplementations

其定义如下
image.png

image.png
使用方式如下:

先创建一个UIViewController的分类
image.png
然后在UIViewController+mylog.m文件里写入下面的代码

#import "UIViewController+mylog.h"
#import <objc/runtime.h>



@implementation UIViewController (mylog)
+(void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //交换appear
        Method org_viewDidAppear = class_getInstanceMethod(**self**, **@selector**(viewDidAppear:));
        Method new_viewDidAppear = class_getInstanceMethod(**self**, **@selector**(myViewDidAppear:));
        method_exchangeImplementations(org_viewDidAppear, new_viewDidAppear);
    
        //交换disappear
        Method org_viewDidDisappear = class_getInstanceMethod(**self**, **@selector**(viewDidDisappear:));
        Method new_viewDidDisappear = class_getInstanceMethod(**self**, **@selector**(myViewDidDisappear:));
        method_exchangeImplementations(org_viewDidDisappear, new_viewDidDisappear);
    });
}

- (void)myViewDidAppear:(BOOL)animated{
    NSLog(@"%@ viewDidAppear",self);
    [self myViewDidAppear:animated];//重定向回到vc的viewDidAppear方法
}

- (void)myViewDidDisappear:(BOOL)animated{
    NSLog(@"%@ viewDidDisappear",self);
    [self myViewDidDisappear:animated];//重定向回到vc的viewDidDisappear方法

}
@end

四、总结

关于runtime代码的使用,我只列出了目前最常用的2个,其实还有很多用法,大家可以上网搜索学习一下,有空我也会补充本文,另外我也会找时间写一下我对runtime运行时消息转发流程的理解,谢谢。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYbBYx8D' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片