Method Swizzling

Method Swizzling是runtime應用的體現,那么關于Method Swizzling的應用和注意事項在下面做簡單的總結:

Method Swizzling原理:

每個類都維護一個方法(Method)列表,Method則包含SEL和其對應IMP的信息,方法交換做的事情就是把SEL和IMP的對應關系斷開,并和新的IMP生成對應關系。

交換前:Asel->AImp Bsel->BImp

交換后:Asel->BImp Bsel->AImp

Method Swizzling用途:

1、面向切面編程: 數據統計;比如為了統計viewwillappear調用的次數,我們可以在基類(其他VC繼承的類)的VC里面,添加如下代碼就可以統計viewwillappear被調用的次數:

+(void)load{//load方法在main()函數執行前就被執行//確保里面的方法被執行一次

??? 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、數組越界問題 。

法一 ? 通過分類強化 :

@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現在叫xxx_new.png那么如果我們在工程中一張一張改名字比較麻煩,所以這個時候可以用“黑魔法”來達到相應的效果。(注意這個方法使用過后三方SDK里面引用的圖片可能也會被改變,所以要謹慎使用,綜合考慮下SDK和自己的圖片數量占比,如果真的想使用就可以在三方SDK中的Bundle圖片資源中,修改三方圖片的名字)。

Method Swizzling注意事項

1、對自己使用Method Swizzling的地方要及時告訴同伴,否則就會在他人調用到此塊方法的時候就會不知所以然。

2、盡量少用Method Swizzling。雖然Method Swizzling可以讓我們高效地解決某些問題,但是如果應用不得當,可能會引發一系列問題。

3、swizzling 需要在 + (void)load{}中使用:

? ? ?在+(void)load{}方法中實現,這樣可以保證方法一定會調用且不會出現異常;使用dispatch_once來執行方法交換,這樣可以保證只運行一次。load 和initialize區別:load是只要類所在文件被引用就會被執行,而initialize是在類或者其子類的第一個方法被調用前調用。所以只有當此類沒有被引用進項目時,才不會調用+(void)load{}方法;如果類文件被引用進來,但是沒有使用,那么initialize也不會被調用;而此時+(void)load{}方法會被調用(在main()函數之前)。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容