[Runtime]-交換方法

1:好比咱們有個需求:讓UIImage加載圖片的時候,告訴咱們是否加載成功了swift

前言:spa

/**
 Runtime(交換方法):只要是想修改系統的方法實現
 
 *  1: 需求:讓UIImage加載圖片,告訴我是否加載成功、給系統UIImageName添加功能,只能使用Runtime
 *  2: //解決辦法一:自定義UIImage方法、重寫:能夠解決
 *  弊端:1:每次使用,都須要導入
         2:若是項目開發好久了,如今這樣一個一個改很麻煩
 
 *  3: //解決辦法二:只能給UIImage添加分類,使用Runtime
         1:給系統的方法添加一個分類
         2:本身實現一個帶有拓展功能的方法
         3:交換方法,只須要交換一次
 */code

> 01-咱們想到的方法可能就是自定義UIImage類,拓展這個方法:如圖片

  • #import <UIKit/UIKit.h>
    
    @interface XJUIImage : UIImage
    
    + (UIImage *)imageNamed:(NSString *)name ;
    
    @end
    
    
    
    #import "XJUIImage.h"
    
    @implementation XJUIImage
    + (UIImage *)imageNamed:(NSString *)name {
        UIImage *image = [super imageNamed:name];
        if (image) {
            NSLog(@"加載成功");
        }else {
            NSLog(@"加載失敗");
        }
        
        return image;
    }
    @end

而後調用的時候:先導入頭文件內存

  • #import "XJUIImage.h"

最後使用:開發

  • - (void)viewDidLoad {
        [super viewDidLoad];
        UIImage *image = [XJUIImage imageNamed:@"1.png"];
        //UIImage *image = [UIImage xj_imageNamed:@"2.png"];
        //UIImage *image = [UIImage imageNamed:@"3"];
    }

最後就會打印 加載成功 || 加載失敗get

注意:上面這種思路,能夠解決了問題,可是它有一些弊端it

                                > 01-每次使用,都須要導入頭文件io

> 02-若是項目已經開發好久了,你不可能全局的一個一個的這樣修改,直接搞死你class


> 02-咱們可能想要建立一個UIImage分類:可是你若是不使用runtime的話,你仍是須要每次導入頭文件,仍是須要修改方法名

  • // 在分類中,最好不要重寫系統的辦法,通常重寫了,就把系統方法給覆蓋了
    //+ (UIImage *)imageNamed:(NSString *)name {
    //    //super:指向父類,因此在分類不能調用super
    //}
  • #import "UIImage+XJImage.h"
  • UIImage *image = [UIImage xj_imageNamed:@"2.png"];

注意:它的弊端和上面是同樣的問題,不能很好的幫助咱們解決問題。


> 03-使用runtime:交換方法:

  1. 給系統的方法添加一個分類
  2. 本身實現一個帶有拓展功能的方法
  3. 交換方法,只須要交換一次:+(void)load;
  • #import <UIKit/UIKit.h>
    
    @interface UIImage (XJImage)
    + (UIImage *)xj_imageNamed:(NSString *)name;
    @end
    
    
    
    #import "UIImage+XJImage.h"
    #import <objc/message.h>
    
    @implementation UIImage (XJImage)
    
    // 在分類中,最好不要重寫系統的辦法,通常重寫了,就把系統方法給覆蓋了
    //+ (UIImage *)imageNamed:(NSString *)name {
    //    //super:指向父類,因此在分類不能調用super
    //}
    
    
    // 把類加載進內存的時候調用,只會調用一次
    + (void)load {
        // 交換方法:runtime
        
        // 獲取imageNamed
        Method imageNameMethod = class_getClassMethod(self, @selector(imageNamed:));
        
        // 獲取xj_imageNamed
        Method xj_imageNameMethod = class_getClassMethod(self, @selector(xj_imageNamed:));
        
        method_exchangeImplementations(imageNameMethod, xj_imageNameMethod);
    }
    
    
    // 還有一種方式:可是會調用屢次,咱們能夠結合dispatch_once_t:保證只會執行一次,swift中只能使用這個方法,由於swift中沒有load方法
    + (void)initialize {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            
        });
    }
    
    
    // 之後想修改系統的方法,可是又不想重名字,能夠在前面添加前綴
    + (UIImage *)xj_imageNamed:(NSString *)name {
        UIImage *image = [UIImage xj_imageNamed:name];
        
        if (image) {
            NSLog(@"xj--加載成功了");
        }else {
            NSLog(@"xj--加載失敗了");
        }
        
        return image;
    }
    @end

注意:它的好處:

  • 不須要導入任何頭文件
  • 不須要修改系統原來的調用方法,由於咱們使用runtime之後,它調用系統方法就會自動去交換變成調用咱們的方法

 

意見反饋郵件:1415429879@qq.com 歡迎大家的閱讀和讚揚、謝謝!

相關文章
相關標籤/搜索