要學(xué)習(xí)runtime,那就必須了解runtime是什么.runtime是運(yùn)行時(shí)機(jī)制
什么是runtime?
1> runtime是一套底層的C語言API(包含很多強(qiáng)大實(shí)用的C語言數(shù)據(jù)類型、C語言函數(shù))
2> 實(shí)際上,平時(shí)我們編寫的OC代碼,底層都是基于runtime實(shí)現(xiàn)的
- 也就是說,平時(shí)我們編寫的OC代碼,最終都是轉(zhuǎn)成了底層的runtime代碼(C語言代碼)
既然要學(xué)習(xí)runtime,那肯定要知道runtime有什么用
runtime有啥用?
1> 能動(dòng)態(tài)產(chǎn)生一個(gè)類、一個(gè)成員變量、一個(gè)方法
2> 能動(dòng)態(tài)修改一個(gè)類、一個(gè)成員變量、一個(gè)方法
3> 能動(dòng)態(tài)刪除一個(gè)類、一個(gè)成員變量、一個(gè)方法
那么開發(fā)中怎么靈活的把runtime運(yùn)用到我們的項(xiàng)目中呢?
首先我們需要導(dǎo)入頭文件 #import<objc/runtime.h>
其次我們要熟悉runtime中的常用函數(shù)
Ivar * class_copyIvarList : 獲得某個(gè)類內(nèi)部的所有成員變量
Method * class_copyMethodList : 獲得某個(gè)類內(nèi)部的所有方法
Method class_getInstanceMethod : 獲得某個(gè)實(shí)例方法(對(duì)象方法,減號(hào)-開頭)
Method class_getClassMethod : 獲得某個(gè)類方法(加號(hào)+開頭)
method_exchangeImplementations : 交換2個(gè)方法的具體實(shí)現(xiàn)
import: <objc/message.h>消息機(jī)制
objc_msgSend(....)
下面寫段個(gè)簡(jiǎn)單的代碼,讓大家感受一下runtime的強(qiáng)大
1-獲取某個(gè)類中所有方法
+ (void)getInstanceMethodList
{
NSMutableString *methodStr = [NSMutableString string];
// 獲取某個(gè)類中所有方法
// 獲取某個(gè)類中所有方法
// Class:獲取哪個(gè)類的方法
// outCount:類中方法總數(shù)
// class_copyMethodList:只能獲取當(dāng)前類
unsigned int count = 0;
// 獲取Method數(shù)組
Method *methodList = class_copyMethodList(self, &count);
for (int i = 0; i < count; i++) {
// 獲取方法
Method method = methodList[i];
// 獲取方法名
SEL sel = method_getName(method);
[methodStr appendFormat:@"\n%@\n",NSStringFromSelector(sel)];
}
NSLog(@"%@",methodStr);
}
+ (void)getClassMethodList
{
NSMutableString *methodStr = [NSMutableString string];
// 獲取某個(gè)類中所有方法
// 獲取某個(gè)類中所有方法
// Class:獲取哪個(gè)類的方法
// outCount:類中方法總數(shù)
// class_copyMethodList:只能獲取當(dāng)前類
unsigned int count = 0;
// 獲取類對(duì)象類名
NSString *className = NSStringFromClass(self);
// OC -> C .UTF8String
// 獲取元類
Class metaClass = objc_getMetaClass(className.UTF8String);
// 獲取Method數(shù)組
Method *methodList = class_copyMethodList(metaClass, &count);
for (int i = 0; i < count; i++) {
// 獲取方法
Method method = methodList[i];
// 獲取方法名
SEL sel = method_getName(method);
[methodStr appendFormat:@"\n%@\n",NSStringFromSelector(sel)];
}
NSLog(@"%@",methodStr);
}
@end
2-動(dòng)態(tài)的添加方法
//控制器中調(diào)用eat方法
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Person *p = [[Person alloc] init];
// performSelector:調(diào)用未聲明方法
// [p performSelector:@selector(eat)];
[p performSelector:@selector(eat:) withObject:@"213"];
// _cmd:當(dāng)前方法編號(hào),viewDidLoad
// NSLog(@"%@ %@",self,NSStringFromSelector(_cmd));
}
內(nèi)部實(shí)現(xiàn)
@implementation Person
// 定義test的函數(shù),沒有返回值,參數(shù)(id,SEL)
// void:v id:@ SEL->:
void test(id self,SEL _cmd, NSString *str)
{
NSLog(@"自己添加方法%@",str);
}
// 只要調(diào)用了一個(gè)未實(shí)現(xiàn)方法,就會(huì)調(diào)用這個(gè)方法進(jìn)行處理
// sel:就是未實(shí)現(xiàn)方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// [@"eat" isEqualToString:NSStringFromSelector(sel)]
// 判斷下是否是eat方法
if (sel == NSSelectorFromString(@"eat:")){
// 動(dòng)態(tài)添加eat方法
// class:給哪個(gè)類添加方法
// SEL:添加哪個(gè)方法
// IMP:方法實(shí)現(xiàn),函數(shù)名:函數(shù)入口
// types:添加的方法類型
class_addMethod(self, sel, (IMP)test, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
3.動(dòng)態(tài)的添加屬性
/*
給系統(tǒng)的類添加一個(gè)屬性,就需要使用runtime,設(shè)置關(guān)聯(lián).
NSObject類添加屬性
*/
- (void)setName:(NSString *)name
{
// 根本就沒有成員變量保存
// _name = name;
// 設(shè)置關(guān)聯(lián)
// 如何保存變量
// object:給哪個(gè)對(duì)象添加屬性
// key:屬性名稱
// value:就是需要保存到對(duì)象中值
// policy:保存策略
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
// 獲取關(guān)聯(lián)
return objc_getAssociatedObject(self, "name");
// return _name;
}
runtime還有很多強(qiáng)大的方法,大家有興趣可以自己慢慢摸索。這里就不再一一介紹了。