iOS運行時函數替換框架——RSSwizzle

iOS運行時函數替換框架——RSSwizzle

1、引言

        Objective-C是的運行時特性在iOS開發中應用普遍,經過runtime方法,開發者能夠在運行時動態爲類添加方法,修改類的方法,系統的class_addMethod()方法和class_replaceMethod()方法能夠十分簡單的添加和修改方法,然而,直接使用這兩個函數有時並不安全,其主要問題有以下幾點:git

1.在進行動態函數修改的時候,有可能其餘線程也在作一樣的操做。github

2.在繼承中,子類執行父類替換的方法會出現問題。安全

3.函數的替換必須依靠_cmd參數。框架

4.可能會出現命名衝突。函數

有關Objective-C運行時的相關內容可在以下博客中查看:http://my.oschina.net/u/2340880/blog/489072spa

        RSSwizzle框架能夠解決上面全部問題,在要求比較高的項目中若是須要使用到運行時函數替換的需求,能夠直接使用這個框架。git地址以下:.net

https://github.com/rabovik/RSSwizzle線程

2、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

相關文章
相關標籤/搜索