Runtime 應用(一)攔截系統自帶的方法交換實現


 

動態的交換方法能夠給項目中大量已經使用的方法 進行攔截增加操作

實踐:利用運行時交換系統的ImageNamed:方法

應用背景

當系統需要適配ios7和ios8時可能會有顯示不同圖片的需求,但在老項目上開發ios7程序時並未考慮到ios8的適配,當項目上有幾百處地方用到ImageNamed:方法時,如果選用最直接的辦法,在該方法之前進行判斷,如果為ios8就顯示另外一張圖片,這樣的工作量明顯會很大,所以可以用運行時的方法來解決。

新建一個項目,准備兩張圖片,一張圖片名為close為ios7而准備,一張close_os8為ios8而准備

 

在storyboard里添加兩個個UIImageView控件

 

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *img1;
@property (weak, nonatomic) IBOutlet UIImageView *img2;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.img1.image = [UIImage imageNamed:@"close"];
    self.img2.image = [UIImage imageNamed:@"fire"];
    
}

@end

 

接下來使用運行時的方法交換imageNamed:的實現,先為UiImage添加一個自定義的創建圖片的分類,此時需要導入一個運行時框架 #import<objc/runtime.h>,

代碼如下:

/**
 *  自定義創建圖片方法
 */
+ (instancetype)imageWithName:(NSString *)name
{
    NSString *imgN = name;
    double version = [[UIDevice currentDevice].systemVersion doubleValue];
    NSLog(@"%f",version);
    if (version >= 8.0) {
        imgN = [NSString stringWithFormat:@"%@_os8",name];
        NSLog(@"%@",imgN);
    }
    // 此時imageWithName:的實現在運行時已經被改為imageNamed:的實現
    return [self imageWithName:imgN];
}

在load方法里面實現方法的交換,該方法只會被加載一次

/**
 *  類第一次加載進內存的時候會調用
 */
+ (void)load
{
    // 運行時交換兩個方法的實現
    Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
    Method m2 = class_getClassMethod([UIImage class], @selector(imageWithName:));
    method_exchangeImplementations(m1, m2);
    
}

 如此就利用運行時機制實現了系統方法和自定義方法互相交換實現

 

 

需要了解的知識點

 

一、什么是運行時

     運行時是一套純C語言的API,編譯器最終都會將OC代碼轉化為運行時代碼。

二、運行時常用函數

1、<objc/runtime.h>

* 獲得某個類的類方法 Method class_getClassMethod(Class cls, SEL name)

* 獲得某個對象的對象方法 Method class_getInstanceMethod(Class cls, SEL name)

* 交換兩個方法的實現 void method_exchangeImplementations(Method m1, Method m2)

* 關聯對象(將值value與對象object關聯起來) void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

參數key:將來可以通過key取出這個存儲的值

參數policy:存儲策略(assign、copy、retain)

* 利用參數key將對象中存儲的對應值取出 id objc_getAssociatedObject(id object, const void *key)

* 獲得某個類的所有成員變量 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)(outCount會返回成員變量的總數)

* 獲得成員變量的名字 const char *ivar_getName(Ivar v)

* 獲得成員變量的類型 const char *ivar_getTypeEncoding(Ivar v)

* 釋放內存 void      free(void *) (當C語言函數名中包含了copy、create、retain、new等詞語,那么就需要在最后釋放資源)

2、<objc/message.h>

* 給某個對象發送某個消息 void objc_msgSend(void)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM