作者:代培 地址:http://blog.csdn.net/dp948080952/article/details/54882811 轉載請注明出處
這篇文章不是介紹什么是方法交換,這類文章很多,如果你不知道什么是方法交換可以看這篇文章:Method Swizzling
方法交換是很危險的東西,會產生一些未知的錯誤,最近在使用方法交換時就遇到了這樣的問題,在我交換了一個系統方法后,在調用這個方法時會在我交換的方法中循環無法跳出。
最終我找到了問題的關鍵,那就是這個方法可能不存在!
每次iOS版本的更新都會出現一些新的API,這些API在之前的版本中就不存在,而你在交換一個方法時如果不考慮它是否存在,那就會導致嚴重的錯誤。
比如我曾經交換過一個方法:
- (void)openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion這個方法只在iOS10之后有,別人在使用的時候也會先判斷這個方法是否會被響應,但是我們看下面的交換代碼會先添加這個方法,如果這個方法不存在,那么本來不會響應就變成了會響應,那么在iOS10之前的系統就會進入這個方法,導致死循環。
Class class = [self class]; Method method1 = class_getInstanceMethod(class, sel1); Method method2 = class_getInstanceMethod(class, sel2); BOOL didAddMethod = class_addMethod(class, sel1, method_getImplementation(method2), method_getTypeEncoding(method2)); if (didAddMethod) { class_replaceMethod(class, sel2, method_getImplementation(method1), method_getTypeEncoding(method1)); } else { method_exchangeImplementations(method1, method2); }解決這個問題也很簡單就是交換前做一個判斷:
if (![class instancesRespondToSelector:sel1] || ![class instancesRespondToSelector:sel2]) { return ; }如果不響應這個方法,直接返回。
為了不重復寫方法交換的代碼,也能減少錯誤,我們可以將其封裝,將其放在NSObject的Category中再合適不過了。
NSObject+DPExtension.h
#import <Foundation/Foundation.h>@interface NSObject (DPExtension)+ (void)intanceMethodExchangeWithOriginSelector:(SEL)sel1 swizzledSelector:(SEL)sel2;@endNSObject+DPExtension.m
#import "NSObject+DPExtension.h"#import <objc/runtime.h>@implementation NSObject (DPExtension)+ (void)intanceMethodExchangeWithOriginSelector:(SEL)sel1 swizzledSelector:(SEL)sel2 { Class class = [self class]; if (![class instancesRespondToSelector:sel1] || ![class instancesRespondToSelector:sel2]) { return ; } Method method1 = class_getInstanceMethod(class, sel1); Method method2 = class_getInstanceMethod(class, sel2); BOOL didAddMethod = class_addMethod(class, sel1, method_getImplementation(method2), method_getTypeEncoding(method2)); if (didAddMethod) { class_replaceMethod(class, sel2, method_getImplementation(method1), method_getTypeEncoding(method1)); } else { method_exchangeImplementations(method1, method2); }}@end就是這些^_^
|
新聞熱點
疑難解答