01 runtime用法之发送消息

作者: 小码码 | 来源:发表于2017-03-24 16:27 被阅读29次

    1 runtime简介

    • RunTime简称运行时。OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
    • 对于C语言,函数的调用在编译的时候会决定调用哪个函数。
      对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
    • 事实证明:
      在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错。
      在编译阶段,C语言调用未实现的函数就会报错。

    2 消息机制验证

    • 2.1 在xcode中创建一个Command Line(命令行)工程,在main.m文件中写上以下两句代码:
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
          // 创建并初始化一个object对象
            NSObject *object= [NSObject alloc];
            object = [object init];
        }
        return 0;
    }
    
    • 2.2 OC代码转换成C++格式
    • cd /Users/Desktop/Clang 进入到main.m所在的文件夹
    • clang -rewrite-objc main.m 执行此命令,将oc转化成C++
      此时文件夹中多了一个main.cpp文件
    • 打开main.cpp,发现main.m文件转化成了10多万行C++代码,以下是被转换后的main函数中的代码:
    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
            NSObject *object= ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc"));
            object = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)object, sel_registerName("init"));
        }
        return 0;
    }
     alloc对应的函数 :  objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
     init对应的函数:  objc_msgSend(object, sel_registerName("init"));
    // 第一个参数:谁发送消息,类名
    // 第二个参数:发送一个什么样的消息,方法名
    

    3 objc_msgSend方法的使用

    • 导入头文件#import <objc/message.h>
    • 取消objc_msgSend方法使用的限制
      xcode6以后,苹果不希望我们使用runtime,对objc_msgSend实行了注释,如下:
    OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ )
    

    要想使用runtime方法,需要进行如下配置:


    • 使用举例
      • 举例1:
    // OC写法:
    NSObject *objc = [NSObject alloc];
    objc = [objc init];
    // 纯runtime写法
    NSObject *objc = objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"));
    objc = objc_msgSend(objc, sel_registerName("init"));
    // runtime与OC的混合写法
    NSObject *objc = objc_msgSend([NSObject class]), @selector(alloc));
    objc = objc_msgSend(objc, @selector(init));
    备注:
        // 谁的事情谁开头 -> 对象(objc)
        // objc_getClass(<#const char *name#>):根据类名获取类对象
        // 类方法用类对象,对象方法用对象
    
    • 举例2:
    (1)场景:创建一个person类,并实现两个私有方法(没有声明的方法):
    - (void)eat{  
        NSLog(@"吃东西");
    }
    
    - (void)run:(NSString *)name metre:(int)metre
    {
        NSLog(@"%@跑了%d米", name ,metre);
    }
    
    (2)实现过程代码
        // 分配内存
        Person *p = objc_msgSend([Person class], @selector(alloc)); 
        // 初始化
        p = objc_msgSend(p, @selector(init));
        // 调用eat方法(没有参数)
        objc_msgSend(p, @selector(eat)); 
        // 调用run方法(有参数)
        objc_msgSend(p, @selector(run:metre:),@"小明", 100);
    

    4 消息机制使用场景

    • 1.封装自己框架,尽量少的暴露接口,装逼用
    • 2.调用私有的方法,前提:知道已经实现,只是没有声明暴露出来

    相关文章

      网友评论

        本文标题:01 runtime用法之发送消息

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