iOS详解runtime面试工作

runtime概念:
什么情况下用runtime?
runtime 消息机制的调用流程 || 能体现runtime 强大之处的应用场景?

runtime概念

Objective-C是基于C的,它为C添加了面向对象的特性。它将很多静态语言在编译和链接时期做的事放到了runtime运行时来处理,可以说runtime是我们Objecttive-C的幕后工作者。

runtime是一套纯C的API。而OC就是运行时机制,最主要的是消息机制。

OC的函数调用成为消息发送,属于动态调用过程。在编译的时候并不能决定真正调用哪个函数,只有在真心运行的时候才根据函数名称找到对应的函数来调用。

runtime 消息机制

我们写OC代码,它在运行的时候也是转换成了runtime方式运行的,任何方法调用的本质:就是发送一个消息(用runtime发送消息,OC底层通过runtime实现)。

消息机制原理:对象根据方法编号SEL去映射表查找对应的方法实现。每一个OC的方法,底层必然有一个与之对应的tuntime方法。

runtime 方法调用流程「消息机制」

1.OC 在向一个对象发送消息时,runtime 库会根据对象的 isa指针找到该对象对应的类或其父类中查找方法。。
2.注册方法编号(这里用方法编号的好处,可以快速查找)。
3.根据方法编号去查找对应方法。
4.找到只是最终函数实现地址,根据地址去方法区调用对应函数。

每一个对象内部都有一个isa指针,这个指针是指向它的真实类型,根据这个指针就能知道将来调用哪个类的方法。

runtime 常见作用

动态交换两个方法的实现
动态添加属性
实现字典转模型的自动转换
发送消息
动态添加方法
拦截并替换方法
实现 NSCoding 的自动归档和解档

runtime应用场景

当第三方框架 或者 系统原生方法功能不能满足我们的时候,我们可以在保持系统原有方法功能的基础上,添加额外的功能。

需求:加载一张图片直接用[UIImage imageNamed:@”image”];是无法知道到底有没有加载成功。给系统的imageNamed添加额外功能(是否加载图片成功)。

方案一:继承系统的类,重写方法.(弊端:每次使用都需要导入)
方案二:使用 runtime,交换方法.

实现步骤:
1.给系统的方法添加分类
2.自己实现一个带有扩展功能的方法
3.交换方法,只需要交换一次。

- (void)viewDidLoad {

    [super viewDidLoad];
    // 方案二:交换 imageNamed 和 ln_imageNamed 的实现,就能调用 imageNamed,间接调用 ln_imageNamed 的实现。
    UIImage *image = [UIImage imageNamed:@"123"];
}

#import
@implementation UIImage (Image)
/**
 load方法: 把类加载进内存的时候调用,只会调用一次
 方法应先交换,再去调用
 */
+ (void)load {
    // 1.获取 imageNamed方法地址
    // class_getClassMethod(获取某个类的方法)
    Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));
    // 2.获取 ln_imageNamed方法地址
    Method ln_imageNamedMethod = class_getClassMethod(self, @selector(ln_imageNamed:));
    // 3.交换方法地址,相当于交换实现方式;「method_exchangeImplementations 交换两个方法的实现」
    method_exchangeImplementations(imageNamedMethod, ln_imageNamedMethod);
}

// 加载图片 且 带判断是否加载成功
+ (UIImage *)ln_imageNamed:(NSString *)name {
    UIImage *image = [UIImage ln_imageNamed:name];
    if (image) {
        NSLog(@"runtime添加额外功能--加载成功");
    } else {
        NSLog(@"runtime添加额外功能--加载失败");
    }
    return image;
}

/**

 不能在分类中重写系统方法imageNamed,因为会把系统的功能给覆盖掉,而且分类中不能调用super
 所以第二步,我们要 自己实现一个带有扩展功能的方法.
 + (UIImage *)imageNamed:(NSString *)name {
 }
 */

// 打印输出

2017-02-17 17:52:14.693 runtime[12761:543574] runtime添加额外功能–加载成功

runtime 给分类动态添加属性

原理:给一个类声明属性,其实本质就是给这个类添加关联,并不是直接把这个值的内存空间添加到类存空间。

应用场景:给系统的类添加属性的时候,可以使用runtime动态添加属性方法。

注解:系统 NSObject 添加一个分类,我们知道在分类中是不能够添加成员属性的,虽然我们用了@property,但是仅仅会自动生成get和set方法的声明,并没有带下划线的属性和方法实现生成。但是我们可以通过runtime就可以做到给它方法的实现。

需求:给系统 NSObject 类动态添加属性 name 字符串。

@interface NSObject (Property)
// @property分类:只会生成get,set方法声明,不会生成实现,也不会生成下划线成员属性
@property NSString *name;
@property NSString *height;
@end
@implementation NSObject (Property)
- (void)setName:(NSString *)name {
    // objc_setAssociatedObject(将某个值跟某个对象关联起来,将某个值存储到某个对象中)
    // object:给哪个对象添加属性
    // key:属性名称
    // value:属性值
    // policy:保存策略
    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)name {
   return objc_getAssociatedObject(self, @"name");
}

// 调用
NSObject *objc = [[NSObject alloc] init];
objc.name = @"123";
NSLog(@"runtime动态添加属性name==%@",objc.name);

// 打印输出
2017-02-17 19:37:10.530 runtime[12761:543574] runtime动态添加属性–name == 123

总结:其实,给属性赋值的本质,就是让属性与一个对象产生关联,所以要给NSObject的分类的name属性赋值就是让name和NSObject产生关联,而runtime可以做到这一点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值