1 動態(tài)添加方法的使用場景
對于APP,當某些功能并不是每個人都可以使用時,比如微博會員機制、某些付費才有的功能,這些方法可以采取動態(tài)添加的方式實現(xiàn).
2 為什么需要動態(tài)添加方法?
OC都是懶加載,如果在類中實現(xiàn)方法,在類加載內(nèi)存的時候,就會把方法加載好,放在類的方法列表中,占用內(nèi)存空間封豪。某些方法乙嘀,對于某些人來說可能一輩子都不會使用,就沒有必要添加到內(nèi)存中漏设。
3 performSelector方法之簡介
- performSelector方法是iOS中的一種方法調(diào)用方式荚坞。他可以向一個對象傳遞任何消息挑宠,而不需要在編譯的時候聲明這些方法。所以這也是runtime的一種應用方式颓影。
- performSelector和直接調(diào)用方法的區(qū)別:
- (1)直接調(diào)用方法編譯時會自動校驗各淀,如果方法不存在,在編譯時候就能夠發(fā)現(xiàn)诡挂,編譯器會直接報錯碎浇。
- (2)使用performSelector的話一定是在運行時候才能發(fā)現(xiàn)临谱,如果方法不存在,編譯時不會報錯奴璃,但在運行時一定會崩潰悉默。
- (3)如果使用performSelector的話,他有個最佳伴侶- (BOOL)respondsToSelector:(SEL)aSelector;來判斷在運行時對象是否響應此方法溺健。
4 動態(tài)添加方法的使用舉例
- 添加沒有參數(shù)的方法
// 1.創(chuàng)建Person 對象
Person *p = [[Person alloc] init];
// 2.調(diào)用沒有實現(xiàn)的eat方法
[p performSelector:@selector(eat)];
// 3.在person.m文件中調(diào)用方法:
// 作用:調(diào)用了一個未實現(xiàn)方法時一定會來到這里
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 判斷方法名是不是eat
if (sel == NSSelectorFromString(@"eat")) {
// 動態(tài)添加eat方法
/*
第一個參數(shù):給哪個類添加方法
第二個參數(shù):添加什么方法
第三個參數(shù)IMP:方法實現(xiàn),函數(shù)入口:函數(shù)名
第四個參數(shù):方法類型
v 沒有返回值
@ 對象 id
: 方法
*/
class_addMethod(self, @selector(eat), eat, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
// 4.eat方法實現(xiàn)
// self:方法調(diào)用者
// _cmd:當前方法編號
// 任何一個方法都能調(diào)用self,_cmd,其實任何一個方法都有這兩個隱式參數(shù)
void eat(id self, SEL _cmd)
{
NSLog(@"吃東西");
}
- 添加有參數(shù)的方法
// 2.調(diào)用沒有實現(xiàn)的run方法
[p performSelector:@selector(run:) withObject:@10];
// 3.在person.m文件中調(diào)用方法:
// 作用:調(diào)用了一個未實現(xiàn)方法時一定會來到這里
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 判斷方法名是不是eat
if (sel == NSSelectorFromString(@"run:")) {
// 動態(tài)添加run方法
/*
第一個參數(shù):給哪個類添加方法
第二個參數(shù):添加什么方法
第三個參數(shù)IMP:方法實現(xiàn),函數(shù)入口:函數(shù)名
第四個參數(shù):方法類型
v 沒有返回值
@ 對象 id
: 方法
*/
class_addMethod(self, @selector(run:), run, "v@:@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
// 4.run方法實現(xiàn)
// self:方法調(diào)用者
// _cmd:當前方法編號
// 任何一個方法都能調(diào)用self,_cmd,其實任何一個方法都有這兩個隱式參數(shù)
void run(id self, SEL _cmd, NSNumber *metre)
{
NSLog(@"跑了%@米",metre);
}