iOS中OC的runtime使用场景

iOS中OC的runtime使用场景

run time介绍:

由于OC是一门动态语言,所以他会把一些确定性的工作从编译链接时段推迟到运行时段。所以OC的运行被分成了编译和运行两个阶段,Runtime就是OC运行时的处理系统(一个用C语言的库),他是OC运行的基础;OC的运行时机制最主要是消息机制,对于C语言而言编译期就决定了运行时要调用哪个函数,而OC是动态进行的,在编译期只是确定要调用的函数指针名称,在运行时才会根据函数的指针去确定真正要调用的函数实现,所以我们才可以在运行时进行一些灵活的操作;

runtime.h中方法的定义:

  • 对对象进行操作一般以objc_开头;
  • 对类进行操作一般以class_开头;
  • 对成员变量进行操作一般以ivar_开头;
  • 对属性进行操作一般以property_开头;
  • 对协议进行操作一般以protoco_开头;

以objc_开头的方法是最底层的操作方法,可以获取内存中的加载信息包括类,成员变量,属性,方法等列表信息。

主要的应用场景:

  • 获取内存中所有的类名:
/*
 打印出所有内存中的类名(在load方法中调用)
 */
+(void)logClasses{
    
    unsigned int count = 0;
    Class * classes =  objc_copyClassList(&count);
    for (int i = 0; i < count; i ++) {
        
        const char * className = class_getName(classes[i]);
        NSLog(@"className: %s",className);
    }
}
  • 发送消息的实质(消息机制):
+(void)sendFuncMsg{

    webview * web = [[webview alloc]init];
//  [web loadRequest];//相当于发送以下信息
//id :消息接受对象;SEL:要发送的消息; int:请求码;
    int(*send)(id, SEL, int) = (int(*)(id, SEL, int)) objc_msgSend;//64位下需要如此转换
    send(web, @selector(loadRequest),0);
}
  • MethodSwizer(方法交换),黑魔法逆向开发中用的最多的方法:

+(void)sendFuncMsg{
}

+(void)changeMethoud{
    //获取要交换的方法:
    //self:要获取方法的类。
    //@selector():要获取的方法
    
    Method sendM = class_getClassMethod(self, @selector(sendFuncMsg));
    Method newM = class_getClassMethod(self, @selector(newMethoud));
    
    //交换方法的实现
    method_exchangeImplementations(sendM, newM);
    [self sendFuncMsg];
}

+(void)newMethoud {
    
    NSLog(@"********啊哈哈,恭喜你方法交换成功了!!!!");
}
  • 使用对象的动态绑定在分类中为类动态添加属性:
//category.h
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIView (UIView_cate)

@property(nonatomic,copy)NSString * lm;//要添加的属性
@end

NS_ASSUME_NONNULL_END
//category.m
#import "UIView+UIView_cate.h"
#import <objc/runtime.h>
//属性绑定的key
static const char * k_name = "name";

@implementation UIView (UIView_cate)
//category中添加的属性不会自动生成set、get方法以及带"_"的成员变量,所以需要手动添加set、get方法。(原因在上篇文category中有介绍)
-(NSString*)lm{
    return objc_getAssociatedObject(self, k_name);
}

-(void)setLm:(NSString*)lm{
    objc_setAssociatedObject(self, k_name, lm, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
  • 动态给类添加方法(可以使用category为类添加方法):
//添加的OC方法
-(void)addParametter:(NSString* )value{
    
    NSLog(@"大家好,我是新添加的方法 %@",value);
}

//方法的默认隐式参数(添加的c函数)
void addCMethod(id self, SEL sel, NSString*value){
    
    NSLog(@"大家好,我是新添加的方法 %@",value);
}

//当对象未实现某个方法时就会调用此方法 (为UIView添加方法);
//最后一个参数“ v@: ” 代表方法的类型,其中“v”代表返回值的类型为“void”,“@”表示对象为self, “  :”表示SEL为“ _cmd”,  “@”代表要传入的参数
+(BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(addParametter:)) {
        
        NSLog(@"大家好 %@",NSStringFromSelector(sel));
        //添加oc方法
        class_addMethod(self, sel, class_getMethodImplementation(self, @selector(addParametter:)), "v@:@");
    }
    
    if (sel == @selector(addCMethod:)) {
        //添加c函数
        class_addMethod(self, sel, (IMP)addCMethod, "v@:@");
    }
    return [super resolveInstanceMethod:sel];
}
//在viewController中调用如下
    [view performSelector:@selector(addParametter) withObject:@"人间四月芳菲尽,山寺桃花始盛开!"];

  • 使用runtime进行字典转模型:
+(instancetype)getModelWith:(NSDictionary*)dic{
    
    id objc = [[self alloc]init];
   //使用runtime根据模型中的属性从字典中取出对应的值赋给模型
    unsigned int count = 0;
    Ivar * ivarList = class_copyIvarList(self, &count);
    
    for (int i = 0; i < count; i ++) {
        
        Ivar ivar = ivarList[i];//获取成员变量
        NSString * ivtype = [NSString stringWithCString:ivar_getTypeEncoding(ivar) encoding:NSUTF8StringEncoding];//获取成员变量类型
        NSString * ivname = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding];
        NSString * key = [ivname substringFromIndex:1];//   去掉下划线
        id value = [dic objectForKey:key];
        NSLog(@"ivName: %@    ivType: %@  %@", ivname, key, value);//若有二级字典可以进一步转换
        if ([value isKindOfClass:NSDictionary.class] && ![ivtype hasPrefix:@"NS"]) {
            
           			Class mClass = NSClassFromString(ivtype);
                       value = [mClass getModelWith:value];
       }
        if (value) {
           //此三者有何去区别????(将在下篇kvc中介绍)
           // [objc setObject:value forKey:key];
           // [objc setValue:value forKey:key];
            [objc setValue:value forKeyPath:key];
        }
    }
    return objc;
}

runtime还有很多神奇的用法,此处只是列举了一部分,希望大家一起探索交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值