最近聽了蠻多 runtime 平時(shí)完全用不到的這種言論芍阎,所以慢慢的寫一點(diǎn) runtime 在項(xiàng)目中的應(yīng)用場(chǎng)景躁绸。其中之一就是吮铭,當(dāng)更新的資源包的文件無法正確讀取的時(shí)候矛渴,替換成一張占位圖椎扬。
能看的實(shí)現(xiàn)方法有如下幾種:
- 寫一個(gè)類別方法,在類別中進(jìn)行邏輯處理具温。
- 用原方法蚕涤,但是進(jìn)行動(dòng)態(tài)方法交換。
第一個(gè)缺點(diǎn)其實(shí)很明顯铣猩,當(dāng)團(tuán)隊(duì)成員不斷增加之后揖铜,沒有辦法確保每一個(gè)人都能按照你的規(guī)范來使用工具類別中的指定方法,除非特別想每天抽不止一點(diǎn)時(shí)間 Code Review达皿。
那么第二個(gè)方案帶來的則是一勞永逸天吓,但是在使用的時(shí)候一定要評(píng)估影響。比如:組件化的時(shí)候經(jīng)常會(huì)用到 bundle 來儲(chǔ)存圖片峦椰,并且使用 cocoapods 來進(jìn)行組件管理龄寞,那么獲取圖片的邏輯就要考慮到你取 -imageNamed:
方法獲得的,可能是原圖片汤功,也可能是占位圖物邑。那么就需要做相關(guān)的邏輯處理。
在例子中,我們只是簡(jiǎn)單展示了一下方法交換的使用方式拂封。
// 這是例子茬射,用的是類別實(shí)現(xiàn)。類別的話冒签,我們丟項(xiàng)目里就可以使用了在抛,并不需要再進(jìn)行引入頭文件。
#import "UIImage+PlaceHolderImage.h"
#import <objc/runtime.h>
@implementation UIImage (PlaceHolderImage)
+ (void)load
{
// 獲取 UIImage 方法 -imageNamed: 的 Method
Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
// 獲取 UIImage+PlaceHolderImage 方法 -replaced_imageNamed: 的 Method
Method replaced_imageNamedMethod = class_getClassMethod(self, @selector(replaced_imageNamed:));
// 將兩個(gè)方法進(jìn)行交換萧恕,現(xiàn)在如果調(diào)用 -imageNamed: 則調(diào)用的是下方 +replaced_imageNamed: 的實(shí)現(xiàn)
method_exchangeImplementations(imageNameMethod, replaced_imageNamedMethod);
}
+ (UIImage *)replaced_imageNamed:(NSString *)imageName
{
// 這里是遞歸調(diào)用嗎刚梭?不是。因?yàn)楝F(xiàn)在調(diào)用 +replaced_imageNamed: 實(shí)現(xiàn)則是蘋果框架內(nèi)的 -imageNamed: 的實(shí)現(xiàn)票唆。
UIImage *image = [UIImage replaced_imageNamed:imageName];
if (!image)
{
image = [UIImage replaced_imageNamed:@"placeholder_image"];
}
return image;
}
@end
一個(gè)簡(jiǎn)單的封裝朴读,如下:
#import <objc/runtime.h>
- (void)pd_exchangeSelector:(SEL)originSel toSelector:(SEL)replazSel
{
[[self class] _pd_exchangeSelector:originSel toSelector:replazSel];
}
+ (void)pd_exchangeSelector:(SEL)originSel toSelector:(SEL)replazSel
{
[self _pd_exchangeSelector:originSel toSelector:replazSel];
}
+ (void)_pd_exchangeSelector:(SEL)originSel toSelector:(SEL)replazSel
{
Method originMethod = class_getClassMethod(self, originSel);
Method replazMethod = class_getClassMethod(self, replazSel);
method_exchangeImplementations(originMethod, replazMethod);
}
實(shí)際項(xiàng)目中,建議使用成熟的 Aspects 庫進(jìn)行 AOP 編程走趋,功能強(qiáng)大衅金,穩(wěn)定高效。
本想解析一下 Aspects 庫的簿煌,一看網(wǎng)上很多很多氮唯,就偷個(gè)懶粘一個(gè)鏈接了。