1.方法的交換使用
那么在什么情況下需要使用到這個(gè)呢,讓我來舉個(gè)栗子??,請(qǐng)看以下代碼,如果當(dāng)照片的名字是錯(cuò)誤的話或者為空的話我們并不能及時(shí)的知道呢
UIImage *image = [UIImage imageNamed:@"123"];
首先想到的處理辦法可能是,寫個(gè)UIImage的擴(kuò)充類別,就叫做UIImage+image吧,然后自己定義個(gè)方法進(jìn)行判斷,如下代碼:
+(UIImage *)dm_imageNamed:(NSString *)imageName{
UIImage *image = [UIImage imageNamed:imageName];
if (image == nil) {
NSLog(@"加載image為空");
return nil;
}else{
return image;
}
}
可是每次調(diào)用上述代碼,都需要導(dǎo)入這個(gè)頭文件,會(huì)比較麻煩,這時(shí)候我們就可以用到runtime解決這個(gè)問題,我們可以將系統(tǒng)的imageNamed:
和我們自己定義的dm_imageNamed:
的方法進(jìn)行調(diào)換,即調(diào)用系統(tǒng)的方法就在調(diào)用自定義的方法.需要在分類中加入這個(gè)方法:
+(void)load{
//記載這個(gè)分類的時(shí)候調(diào)用
NSLog(@"*****%s",__func__);
//獲取類方法
//class_getClassMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>)
//獲取對(duì)象方法
//class_getInstanceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>)
//Class獲取哪個(gè)類的方法,SEL:獲取方法編號(hào),根據(jù)SEL就能去對(duì)應(yīng)的類找方法
Method imageName = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method dm_imageName = class_getClassMethod([UIImage class], @selector(dm_imageNamed:));
method_exchangeImplementations(imageName, dm_imageName);
}
這時(shí)候兩個(gè)方法就進(jìn)行互換了,注意,我們還需要將dm_imageNamed:的方法中改成下面這句,否則會(huì)造成循環(huán)引用.
UIImage *image = [UIImage dm_imageNamed:imageName];
這樣,我們就可以盡情的調(diào)用imageNamed:
方法,實(shí)際上執(zhí)行的是dm_imageNamed:
這個(gè)方法.
2.動(dòng)態(tài)添加方法(懶加載模式)
新建一個(gè)Person繼承于NSObject,我們?cè)赩C中執(zhí)行如下代碼,
Person *pp = [[Person alloc]init];
//performSelector:可以根據(jù)方法名找到對(duì)應(yīng)方法
[pp performSelector:@selector(eat)];
動(dòng)態(tài)添加方法,首先要實(shí)現(xiàn)resolveClassMethod,當(dāng)調(diào)用了沒有實(shí)現(xiàn)的方法,那么就會(huì)走這個(gè)方法,當(dāng)然,方法沒有的話程序會(huì)崩潰的哦,所以打斷點(diǎn)看結(jié)果嘛.在Person.m文件寫入如下代碼:
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(eat)) {
//打印出的就是eat這個(gè)方法
NSLog(@"%@",NSStringFromSelector(sel));
return YES;
}
return YES;
}
接下來就說說用runtime如何動(dòng)態(tài)實(shí)現(xiàn),我們這里以一個(gè)可以傳入?yún)?shù)的函數(shù)為栗子??
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(eat:)) {
NSLog(@"啦啦啦啦");
/*class_addMethod(Class cls, SEL name, IMP imp,
const char *types)
參數(shù)分別對(duì)應(yīng):給哪個(gè)類添加方法; 添加方法的編號(hào)是什么;方法的實(shí)現(xiàn),函數(shù)的入口,即指針;方法類型)
*/
class_addMethod(self, sel, eat, "v@:@");
return YES;
}
return YES;
}
其中方法類型這項(xiàng)我們可以參考官方文檔
我們可以看到
V@:@
就代表一個(gè)有參無返回的函數(shù).接下來我們需要實(shí)現(xiàn)這個(gè)函數(shù),并且可以調(diào)用[pp performSelector:@selector(eat:) withObject:@1111]
的方法對(duì)結(jié)果進(jìn)行分析.
void eat(id self,SEL _cmd,id param){
//其中參數(shù)(id,SEL),調(diào)用方法,系統(tǒng)會(huì)默認(rèn)傳入這個(gè)隱式參數(shù)
NSLog(@"%@,%@",param,NSStringFromSelector(_cmd));
}
3.動(dòng)態(tài)方法添加屬性
當(dāng)我們創(chuàng)建一個(gè)分類,并且給分類添加屬性,進(jìn)行相應(yīng)的調(diào)用(catagory本來就不能為原有類添加屬性, 只能添加方法),我們可以通過runtime進(jìn)行屬性綁定,我們創(chuàng)建一個(gè)類別并且申明@property (nonatomic, strong) NSString *name
接下來重寫set和get方法實(shí)現(xiàn).
-(void)setName:(NSString *)name{
/*
參數(shù)分別對(duì)應(yīng):給某個(gè)對(duì)象添加屬性;屬性名,根據(jù)key去獲取關(guān)聯(lián)的對(duì)象;關(guān)聯(lián)的值;策略(這里是傳入字符串)
*/
objc_setAssociatedObject(self,@"name", name, OBJC_ASSOCIATION_RETAIN);
}
-(NSString *)name{
return objc_getAssociatedObject(self, @"name");
}
第一次寫,有不足的地方歡迎指正呢.我也在學(xué)習(xí)runtime中嘞.歡迎交流哦!
以上??