iOS进阶—Runtime基础

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wtdask/article/details/84139048

iOS进阶—目录


GitHub参考

RunTime 基础

一个程序的执行过程,大概就是代码->编译链接->执行

C语言

#import <Foundation/Foundation.h>
void run() {
    NSLog(@"%s", __func__);
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {     
        run();  
    }
    return 0;
}

执行结果:

2018-11-16 11:41:34.373347+0800 Runtime001[2263:82588] run
Program ended with exit code: 0

OC 属于消息发送机制,包含SEL 和IMP,如果把OC理解为一本书,SEL (编号)代表书目录的文章标题,IMP(指针)代表文章对应页码,方法实现本身则是正文

Runtime进行同类方法交换

#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import "TZDog.h"
#import <objc/runtime.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TZPerson* p = [TZPerson new];
        Method m1 = class_getInstanceMethod([p class], @selector(walk));
        Method m2 = class_getInstanceMethod([p class], @selector(run));
        IMP imp = method_getImplementation(m2);
        method_setImplementation(m1, imp);
        [p walk];   
    }
    return 0;
}

执行结果:我们调用的walk,执行的是run方法

2018-11-16 11:49:45.681647+0800 Runtime001[2356:87721] -[TZPerson run]
Program ended with exit code: 0

Method本身是typedef struct objc_method *Method;结构体。我们可以查看Runtime源码(参考GitHub)objc-runtime-master

在这里插入图片描述

上面的代码与下面的代码等价

struct method_t {
    SEL name;
    const char *types;
    IMP imp; 
//    struct SortBySELAddress :
//    public std::binary_function<const method_t&,
//    const method_t&, bool>
//    {
//        bool operator() (const method_t& lhs,
//                         const method_t& rhs)
//        { return lhs.name < rhs.name; }
//    };
};
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TZPerson* p = [TZPerson new];
        Method m1 = class_getInstanceMethod([p class], @selector(walk));
        struct method_t * m2 = class_getInstanceMethod([p class], @selector(run));
//        IMP imp = method_getImplementation(m2);
        method_setImplementation(m1, m2->imp);
        [p walk];
    }
    return 0;
}

OC在调用类方法时,也可以对C语言的函数进行调用,比如下面的例子

#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import <objc/runtime.h>

void run() {
    NSLog(@"%s", __func__);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TZPerson* p = [TZPerson new];
        Method m1 = class_getInstanceMethod([p class], @selector(walk));
        method_setImplementation(m1, (IMP)run);
        [p walk];        
    }
    return 0;
}

OC进行调用类交换,如下

#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import "TZDog.h"
#import <objc/runtime.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        TZPerson* p = [TZPerson new];
        TZDog* d = [TZDog new];
        object_setClass(p, [d class]);
        [p walk];        
    }
    return 0;
}

执行结果如下:

2018-11-16 14:39:19.802920+0800 Runtime001[3662:134196] -[TZDog walk]
Program ended with exit code: 0

本来调用的Person,但是替换成了Dog类。这就是类对象发送改变。

GitHub参考
iOS进阶—目录


猜你喜欢

转载自blog.csdn.net/wtdask/article/details/84139048