Method Swizzling是runtime應(yīng)用的體現(xiàn)辣辫,那么關(guān)于Method Swizzling的應(yīng)用和注意事項(xiàng)在下面做簡單的總結(jié):
Method Swizzling原理:
每個類都維護(hù)一個方法(Method)列表,Method則包含SEL和其對應(yīng)IMP的信息空入,方法交換做的事情就是把SEL和IMP的對應(yīng)關(guān)系斷開络它,并和新的IMP生成對應(yīng)關(guān)系。
交換前:Asel->AImp Bsel->BImp
交換后:Asel->BImp Bsel->AImp
Method Swizzling用途:
1歪赢、面向切面編程: 數(shù)據(jù)統(tǒng)計(jì);比如為了統(tǒng)計(jì)viewwillappear調(diào)用的次數(shù)单料,我們可以在基類(其他VC繼承的類)的VC里面埋凯,添加如下代碼就可以統(tǒng)計(jì)viewwillappear被調(diào)用的次數(shù):
+(void)load{//load方法在main()函數(shù)執(zhí)行前就被執(zhí)行//確保里面的方法被執(zhí)行一次
??? static dispatch_once_t onceToken;????
dispatch_once(&onceToken, ^{???????
?[self swizzingClass:[self class] originSel:@selector(viewWillAppear:) newSel:@selector(custom_viewWillAppear:)];???
?});
}
+(void)swizzingClass:(Class)class? originSel:(SEL)originSel? newSel:(SEL)newSel{??? Method originM = class_getInstanceMethod(class, originSel);????
Method newM = class_getInstanceMethod(class, newSel);???
?IMP newImp = method_getImplementation(newM);???
?BOOL addMethodSuccess = class_addMethod(class, newSel, newImp, method_getTypeEncoding(newM));????
if (addMethodSuccess) {???????
?class_replaceMethod(class, originSel, newImp, method_getTypeEncoding(newM));??? }else{????????
method_exchangeImplementations(originM, newM);???
?}??
?}
-(void)custom_viewWillAppear:(BOOL)animate{??
? [super viewWillAppear:animate];????
NSLog(@"%@========%s",[self class],__func__);
}
2、數(shù)組越界問題 扫尖。
法一 ? 通過分類強(qiáng)化 :
@implementation?UIView?(safe)
-?(BOOL)containsObjectAtIndex:(NSInteger)index?{
return?index?>=?0?&&?index?
}
-?(id)objectNilAtIndex:(NSInteger)index{
return?[self?containsObjectAtIndex:index]???[self?objectAtIndex:index]?:?nil;
}
@end
法二 ?使用Method sizzling
@implementation NSArray (StrengThen)
+?(void)load{
static?dispatch_once_t?onceToken;
dispatch_once(&onceToken,?^{
@autoreleasepool?{
[objc_getClass("__NSArray0")?swizzleMethod:@selector(objectAtIndex:)?swizzledSelector:@selector(emptyObjectIndex:)];
[objc_getClass("__NSArrayI")?swizzleMethod:@selector(objectAtIndex:)?swizzledSelector:@selector(arrObjectIndex:)];
[objc_getClass("__NSArrayM")?swizzleMethod:@selector(objectAtIndex:)?swizzledSelector:@selector(mutableObjectIndex:)];
[objc_getClass("__NSArrayM")?swizzleMethod:@selector(insertObject:atIndex:)?swizzledSelector:@selector(mutableInsertObject:atIndex:)];
}
});
}
-?(id)emptyObjectIndex:(NSInteger)index{
return?nil;}
-?(id)arrObjectIndex:(NSInteger)index{
if?(index?>=?self.count?||?index?<?0)?{
return?nil;
return?[self?arrObjectIndex:index];
}
-?(id)mutableObjectIndex:(NSInteger)index{
if?(index?>=?self.count?||?index?<?0)?{
return?nil;
}
return?[self?mutableObjectIndex:index];
}
-?(void)mutableInsertObject:(id)object?atIndex:(NSUInteger)index{
if?(object)?{
[self?mutableInsertObject:object?atIndex:index];
}
?}
?3白对、給全局圖片名稱添加后綴,比如你的工程所有的圖片都更新了换怖,以前都叫xxx.png現(xiàn)在叫xxx_new.png那么如果我們在工程中一張一張改名字比較麻煩甩恼,所以這個時候可以用“黑魔法”來達(dá)到相應(yīng)的效果。(注意這個方法使用過后三方SDK里面引用的圖片可能也會被改變,所以要謹(jǐn)慎使用条摸,綜合考慮下SDK和自己的圖片數(shù)量占比悦污,如果真的想使用就可以在三方SDK中的Bundle圖片資源中,修改三方圖片的名字)钉蒲。
Method Swizzling注意事項(xiàng)
1切端、對自己使用Method Swizzling的地方要及時告訴同伴,否則就會在他人調(diào)用到此塊方法的時候就會不知所以然顷啼。
2踏枣、盡量少用Method Swizzling。雖然Method Swizzling可以讓我們高效地解決某些問題钙蒙,但是如果應(yīng)用不得當(dāng)茵瀑,可能會引發(fā)一系列問題。
3躬厌、swizzling 需要在 + (void)load{}中使用:
? ? ?在+(void)load{}方法中實(shí)現(xiàn)马昨,這樣可以保證方法一定會調(diào)用且不會出現(xiàn)異常;使用dispatch_once來執(zhí)行方法交換烤咧,這樣可以保證只運(yùn)行一次偏陪。load 和initialize區(qū)別:load是只要類所在文件被引用就會被執(zhí)行,而initialize是在類或者其子類的第一個方法被調(diào)用前調(diào)用煮嫌。所以只有當(dāng)此類沒有被引用進(jìn)項(xiàng)目時笛谦,才不會調(diào)用+(void)load{}方法;如果類文件被引用進(jìn)來昌阿,但是沒有使用饥脑,那么initialize也不會被調(diào)用;而此時+(void)load{}方法會被調(diào)用(在main()函數(shù)之前)懦冰。