runtime是什么
runtime官脓,即運(yùn)行時(shí)機(jī)制。
runtime是一套底層的純C的API前标,是一個(gè)C語言庫坠韩。
平時(shí)寫的OC代碼,最終都會(huì)轉(zhuǎn)成runtime的C語言代碼炼列,runtime的幕后工作者只搁。
比如:
在OC中:
[[Person alloc] init];
在runtime中:
objc_msgSend(objc_msgSend("Person","alloc"),"init");
runtime的應(yīng)用
- 攔截系統(tǒng)的方法調(diào)用
- 把OC代碼轉(zhuǎn)換為運(yùn)行時(shí)代碼,探究底層俭尖,比如block的內(nèi)部實(shí)現(xiàn)
- 字典轉(zhuǎn)模型
- 在程序運(yùn)行的狀態(tài)中氢惋,動(dòng)態(tài)創(chuàng)建一個(gè)類 (比如KVO底層的實(shí)現(xiàn))
- 在程序運(yùn)行的狀態(tài)中,動(dòng)態(tài)地為某個(gè)類添加屬性/方法稽犁,修改屬性值/方法(分類增加屬性焰望。
有人說分類不能增加屬性,這是不準(zhǔn)確的已亥,分類可以增加屬性柿估,并且會(huì)自動(dòng)生成聲明,但不會(huì)自動(dòng)生成get/set方法陷猫,這時(shí)就需要借助runtime來實(shí)現(xiàn))
#import <Foundation/Foundation.h>
@interface NSObject (Ex)
@property (nonatomic, copy) NSString *name;
@end
#import "NSObject+Ex.h"
#import <objc/runtime.h>
char namekey;
@implementation NSObject (Ex)
//關(guān)聯(lián)對(duì)象函數(shù)
// id object被關(guān)聯(lián)的對(duì)象
// const void *key關(guān)聯(lián)鍵
// id value 關(guān)聯(lián)值
// objc_AssociationPolicy policy 關(guān)聯(lián)策略
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self, &namekey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self, &namekey);
}
@end
- 遍歷一個(gè)類的成員變量(屬性)
相關(guān)方法和頭文件
頭文件
<objc/runtime.h>
<objc/message.h>方法
NSCoding(歸檔和解檔)
字典轉(zhuǎn)模型(利用runtime遍歷模型對(duì)象的所有屬性秫舌,根據(jù)屬性名從字典里取出相應(yīng)的值的妖,設(shè)置到模型的屬性上)
KVO(利用runtime動(dòng)態(tài)產(chǎn)生一個(gè)類)
objc_msgsend給對(duì)象發(fā)送消息
class_copymethodList遍歷某個(gè)類的方法
class_copyIvarList遍歷某個(gè)類的成員變量
class_...
class_getClassMethod 獲取類方法
method_exchangeImplementations 方法交換
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
view.image = [UIImage imageNamed:@"pic_1"];
[self.view addSubview:view];
}
@end
#import "UIImage+ExTension.h"
#import <objc/runtime.h>
@implementation UIImage (ExTension)
//+ (void)load 只在加載時(shí)調(diào)用一次
+ (void)load{
NSLog(@"image load");
//get類方法
Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method m2 = class_getClassMethod([UIImage class], @selector(my_imageNamed:));
//方法交換
method_exchangeImplementations(m1, m2);
}
//自定義方法
+ (UIImage *)my_imageNamed:(NSString *)name{
//方法已經(jīng)被置換,所以此時(shí)調(diào)用的my_imageNamed:實(shí)際上調(diào)用的是原方法imageNamed:
return [UIImage my_imageNamed:@"pic_2"];
}
@end
程序執(zhí)行結(jié)果顯示的就是pic_2,而不是pic_1足陨。方法交換可以用于攔截在運(yùn)行時(shí)攔截一些方法嫂粟,在執(zhí)行完自己想要的操作后再跳回該方法。
- +(void)load 是一個(gè)類方法 它在加載進(jìn)內(nèi)存時(shí)會(huì)調(diào)用一次
- +(void)initialize 會(huì)在第一次調(diào)用類的類方法或?qū)嵗椒ㄖ氨徽{(diào)用一次墨缘。
runtime常識(shí):
Ivar:成員變量星虹,在runtime中,變量只有一個(gè)數(shù)據(jù)類型镊讼,就是Ivar
Method:成員方法