runtime相关iOS学习笔记

runtime解析及常用方法

2016-03-27  本文已影响147人  其字德安

什么是runtime?

查看runtime底层实现:

    // 测试代码
    Person *p = [Person alloc];
    p = [p init];

生成cpp文件,找到对应代码:


    Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc"));

    p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("init"));

解析: 简化代码后,其实runtime底层也就是调用苹果封装的方法而已

   (Person *(*)(id, SEL))(void *) 强制类型转换, 把objc_msgSend转换成有返回值(Person *), 两个参数(id, SEL)的指向函数的指针;故可去掉,简化代码如下:

    Person *p = objc_msgSend([Person class], @selector(alloc));
    p = objc_msgSend(p, @selector(init));

由于苹果不推荐我们使用其底层的runtime, 但是有时一些功能只能由runtime实现,故我们首先配置Xcode(以XCocde7为例)
Snip20160327_1.png

runtime常用方法:

代码实现:

@implementation Person

// 定义函数
// 默认OC方法都有两个隐式参数,self,_cmd
void run(id self, SEL _cmd) {
    NSLog(@"run");
}

// 只要调用没有实现的方法 就会来到方法
// 作用:去解决没有实现方法,动态添加方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{

    if (sel == @selector(run)) {
        // 添加方法
        class_addMethod(self, sel, (IMP)run, nil);

        return YES;
    }

    return [super resolveInstanceMethod:sel];
}

@end

方法解析:
    // 添加方法到类
    class_addMethod(__unsafe_unretained Class cls, SEL name, IMP imp, const char *types);

        class:给谁添加方法
        SEL:添加哪个方法
        IMP:方法实现,函数入口,传入函数名
        type:方法类型 默认nil即可

然后我们利用performSelector方法调用一个没有实现的方法:

    [p performSelector:@selector(run)]

    // 会自动执行上面方法添加一个动态方法run
    // 打印输出:run

tips:

// 没有实现对象方法时,调用该方法
+(BOOL)resolveInstanceMethod:(SEL)sel {

    // 添加方法
}

// 没有实现类方法时, 调用该方法
+(BOOL)resolveClassMethod:(SEL)sel {

    // 添加方法
}

此时可以使用runtime的动态交换方法来实现功能:

#import "UIImage+image.h"
#import <objc/message.h>

@implementation UIImage (image)
+(void)load {

    // 1.0 获取方法
    Method abel_imageNamed = class_getClassMethod(self, @selector(abel_imageNamed:));
    Method imageNamed = class_getClassMethod(self, @selector(imageNamed:));

    // 2.0 交换方法的实现
    method_exchangeImplementations(abel_imageNamed, imageNamed);

}

// 添加该功能方法
+ (UIImage *)abel_imageNamed:(NSString *)name
{
    // 调用系统方法
    UIImage *image = [self abel_imageNamed:name];

    // 添加功能
    if (image == nil) {

        NSLog(@"加载失败");
    }
    return image;
}

@end

上一篇下一篇

猜你喜欢

热点阅读