Objective-C是的運行時特性在iOS開發中應用普遍,經過runtime方法,開發者能夠在運行時動態爲類添加方法,修改類的方法,系統的class_addMethod()方法和class_replaceMethod()方法能夠十分簡單的添加和修改方法,然而,直接使用這兩個函數有時並不安全,其主要問題有以下幾點:git
1.在進行動態函數修改的時候,有可能其餘線程也在作一樣的操做。github
2.在繼承中,子類執行父類替換的方法會出現問題。安全
3.函數的替換必須依靠_cmd參數。框架
4.可能會出現命名衝突。函數
有關Objective-C運行時的相關內容可在以下博客中查看:http://my.oschina.net/u/2340880/blog/489072。spa
RSSwizzle框架能夠解決上面全部問題,在要求比較高的項目中若是須要使用到運行時函數替換的需求,能夠直接使用這個框架。git地址以下:.net
https://github.com/rabovik/RSSwizzle。線程
RSSwizzle中提供了兩種使用方式,一種是經過調用類方法來實現函數的替換,另外一種是使用RSSwizzle定義的宏來進行函數的替換。使用類方法的方式示例以下:code
- (void)viewDidLoad { [super viewDidLoad]; //替換類方法 [RSSwizzle swizzleClassMethod:NSSelectorFromString(@"log") inClass:NSClassFromString(@"ViewController") newImpFactory:^id(RSSwizzleInfo *swizzleInfo) { return ^(__unsafe_unretained id self){ NSLog(@"Class log Swizzle"); }; }]; } +(void)log{ NSLog(@"Class log"); }
這個函數用來替換類方法,第1個參數爲要替換的函數選擇器,第2個參數爲要替換此函數的類,block參數中須要返回一個方法函數,這個函數爲要替換成的函數,要和原函數類型相同。在類中的函數默認都會有一個名爲self的id參數。進行實例函數的替換實例代碼以下:blog
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //進行實例方法的替換 /* 第一個參數爲要替換的函數,第二個參數爲要替換方法的類,第三個的block中返回替換後的方法,第四個參數設置替換模式,最後一個參數是此替換操做的標識符 */ [RSSwizzle swizzleInstanceMethod:NSSelectorFromString(@"touchesBegan:withEvent:") inClass:NSClassFromString(@"ViewController") newImpFactory:^id(RSSwizzleInfo *swizzleInfo) { return ^(__unsafe_unretained id self,NSSet* touches,UIEvent* event){ NSLog(@"text Swizzle"); }; } mode:RSSwizzleModeAlways key:@"key"]; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ NSLog(@"test"); [ViewController log]; }
替換模式的枚舉RSSwizzleMode意義以下:
typedef NS_ENUM(NSUInteger, RSSwizzleMode) { //任何狀況下 始終執行替換操做 RSSwizzleModeAlways = 0, //相同key標識的替換操做只會被執行一次 RSSwizzleModeOncePerClass = 1, //相同key標識的替換操做在子類父類中只會被執行一次 RSSwizzleModeOncePerClassAndSuperclasses = 2 };
使用宏的模式進行方法替換操做的代碼更加簡單,示例以下:
//進行類方法的替換 /* 第1個參數爲要替換方法的類 第二個參數爲要替換的方法選擇器 第三個參數爲方法的返回值類型,第四個參數爲方法的參數列表,最後一個參數爲要替換的方法代碼塊 */ RSSwizzleClassMethod(NSClassFromString(@"ViewController"), NSSelectorFromString(@"log"), RSSWReturnType(void), RSSWArguments(), RSSWReplacement( { //先執行原始方法 RSSWCallOriginal(); NSLog(@"Class log Swillze"); })); //進行實例方法的替換 /* 第一個參數爲要替換方法的類,第二個參數爲要替換的方法選擇器,第三個參數爲返回值類型,第四個參數爲參數列表 第五個參數爲要替換的代碼塊,第六個參數爲執行模式,最後一個參數爲key值標識。 */ RSSwizzleInstanceMethod(NSClassFromString(@"ViewController"),NSSelectorFromString(@"touchesBegan:withEvent:"), RSSWReturnType(void), RSSWArguments(NSSet* touchs,UIEvent * event), RSSWReplacement({ NSLog(@"test Swizzle"); }), RSSwizzleModeAlways, @"key");
在宏內,能夠直接調用RSSWCallOriginal()來執行替換前的原始函數,十分方便。
專一技術,熱愛生活,交流技術,也作朋友。
——琿少 QQ羣:203317592