iOS runtime机制和使用

作者: 遛遛食 | 来源:发表于2017-06-29 16:03 被阅读4525次

    runtime简称运行时。OC是运行时机制,也就是在运行时才做一些处理。例如:C语言在编译的时候就知道要调用哪个方法函数,而OC在编译的时候并不知道要调用哪个方法函数,只有在运行的时候才知道调用的方法函数名称,来找到对应的方法函数进行调用。

    导入

    想要使用runtime,就要先导入runtime库
    一般导入message.h,因为message.h包含了objc.h和runtime.h

    #import “<objc/message.h>”

    runtime作用

    一:发送消息
    OC方法调用原理

    方法调用的本质就是放对象发送消息

    /* new 会调用 init方法 */
    People *man = [People new];
    People *man = [[People alloc] init];
    
    //属性方法调用的方式
    [man eat];
    //类方法调用方式
    [People eat];
    [[People class] eat];
    
    //还有一种不常用的调用方式
    [对象/类 performSelector:@selector(eat)];
    
    //底层实现
    objc_msgSend(对象/属性, @selector(eat));
    

    最终代码查看方法:clang -rewrite-objc main.m
    消息发送底层实现 Build Setting设置msg为NO Xcode5之后使用runtime机制
    OC 与 C 的对应方法
    [People class] == objc_getClass("People")
    @selector() == sel_registerName()

    二:交换方法

    当系统自带的方法功能不够,可以给系统自带的方法扩展一些功能,并保持原有的功能

    例如我想知道当前的URL是否为空如果每次都判断一下的话会很麻烦,如果我创建扩展来写,又不知道内部是如何实现的.

    一:使用继承来实现

    //.h文件内容
    #import <Foundation/Foundation.h>
    
    @interface CFURL : NSURL
    
    +(instancetype)CFURLWithString:(NSString *)string;
    
    @end
    
    -----------------------------------------------
    //.m文件内容
    #import "CFURL.h"
    
    @implementation CFURL
    
    +(instancetype)CFURLWithString:(NSString *)string{
        CFURL *url = [super URLWithString:string];
        if (url == nil) {
            NSLog(@"url为空");
        }
        return url;
    }
    
    @end
    

    二:使用runtime交换方法

    //.h文件内容
    #import <Foundation/Foundation.h>
    
    @interface NSURL (url)
    
    +(instancetype)CF_URLWithStr:(NSString *)URLString;
    
    @end
    
    -----------------------------------------------
    //.m文件内容
    #import "NSURL+url.h"
    
    #import <objc/runtime.h>
    
    @implementation NSURL (url)
    
    +(void)load{
        //最早的方法,比main还早
        NSLog(@"load");
        //1.拿到两个Method
        //2.进行方法交换
        Method m1 = class_getClassMethod([NSURL class], @selector(URLWithString:));
        Method m2 = class_getClassMethod([NSURL class], @selector(CF_URLWithStr:));
        //利用runtime进行方法的交换
        method_exchangeImplementations(m1, m2);
    }
    
    
    +(instancetype)CF_URLWithStr:(NSString *)URLString{
        //交换了两个方法
        NSURL *url = [NSURL CF_URLWithStr:URLString];//注意这里不能再调用系统的方法
        if (!url) {
            NSLog(@"url为空");
        }
        return url;
    }
    
    @end
    

    三:动态添加方法

    //.m文件
    #import "People.h"
    
    #import <objc/runtime.h>
    
    @implementation People
    
    //当类调用一个没有实现的类方法就会到这里!!
    +(BOOL)resolveClassMethod:(SEL)sel{
        NSLog(@"%@",NSStringFromSelector(sel));
        return [super resolveClassMethod:sel];
    }
    
    //当类调用一个没有实现的对象方法就会到这里!!
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
        if (sel == @selector(eat)) {
            // 动态添加eat方法
           /*
             第一个参数:给哪个类添加方法
             第二个参数:添加方法的方法编号
             第三个参数:添加方法的函数实现(函数地址)
             第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd
           */
            class_addMethod(self, @selector(eat), eat, "v@:");
        }
        return [super resolveInstanceMethod:sel];
    }
    
    // 默认方法都有两个隐式参数,
    void eat(id self,SEL sel)
    {
        NSLog(@"%@ %@",self,NSStringFromSelector(sel));
    }
    
    @end
    

    四: 给分类添加属性

    //.h文件
    #import "NSObject.h"
    
    @interface NSObject (Property)
    
    //@property在分类中只会生成set、get方法的声明 不会生成实现,也不会生成_成员属性
    @property (nonatomic,copy)NSString name;
    
    @end
    
    -----------------------------------------------
    //.m文件
    // 定义关联的key
    static const char *key = "name";
    
    @implementation NSObject (Property)
    
    - (NSString *)name
    {
        // 根据关联的key,获取关联的值。
        return objc_getAssociatedObject(self, key);
    }
    
    - (void)setName:(NSString *)name
    {
        /*
         第一个参数:给哪个对象添加关联
         第二个参数:关联的key,通过这个key获取
         第三个参数:关联的value
         第四个参数:关联的策略
       */
        objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    @end
    

    相关文章

      网友评论

      • 雪_晟:如果多个地方交换同一个方法,会执行哪一个方法,执行顺序呢
        雪_晟:@遛遛食 我测试 是执行第一次交换的方法
        遛遛食:多个地方换就看谁是最后执行的

      本文标题:iOS runtime机制和使用

      本文链接:https://www.haomeiwen.com/subject/zbmmcxtx.html