1. 程式人生 > >執行時(runtime)-方法交換

執行時(runtime)-方法交換

1> 建立一個 Person 類,並定義兩個方法 study 和 run,分別實現

#import "Person.h"
@implementation Person
- (void)study {
    NSLog(@"study");
}

- (void)run {
    NSLog(@"run");
}
@end

2> 正常呼叫方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {
    Person *p = [[Person alloc] init];    
    [p study];
    [p run];
}

執行程式,結果如下:
這裡寫圖片描述

3> 交換方法實現

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Person *p = [[Person alloc] init];

        [p study];
        [p run];

        // 交換方法實現
        Method m1 = class_getInstanceMethod(objc_getClass("Person"), @selector(study));
        Method m2 = class_getInstanceMethod(objc_getClass("Person"
), @selector(run)); method_exchangeImplementations(m1, m2); [p study]; [p run]; } return 0; }

執行程式,結果如下:
這裡寫圖片描述

由執行結果可知:study 方法和 run 方法的實現的確被交換了。

4. 交換系統自帶的方法
在實際開發中,交換方法最大的應用場景是`替換系統自帶的方法。
4.1 舉例分析
舉個例子:從iOS6到iOS7,蘋果的介面風格由 ‘擬物化’ 轉變為 ‘扁平化’。
‘怎麼快速適配?’
1> 設定圖片是通過系統的 imageNamed 方法來實現的。
2> 如果要進行iOS7之後版本的適配,首先需要平面設計師做出一套扁平化的圖片,然後對系統版本(systemVersion)進行判斷: 大於7.0就是用扁平化圖片。
3> 如果專案中很多地方都有設定圖片的程式碼,就要在每一處都新增判斷系統版本的程式碼,工作量十分龐大,很不現實。這個時候,就可以考慮使用執行時交換方法來解決問題。
‘解決思路’


1> 假設舊圖片的圖片名為 ‘xxx.png’,可以讓平面設計師將新圖片的圖片名命名為’xxx_ios7.png’
2> 自定義一個 ‘xfq_imageNamed’ 方法,在該方法中進行系統版本判斷,如果大於7.0就使用’xxx_ios7.png’的圖片。
3> 交換自定義的 ‘xfq_imageNamed’ 方法 和 系統的 ‘imageNamed’ 方法的實現

4.2 程式碼實現

1> 自定義 UIImage+Extension 分類

UIImage+Extension.m

#import "UIImage+Extension.h"
#import <objc/runtime.h>

@implementation UIImage (Extension)
/**
 當某個類或者分類載入到記憶體的時候,會呼叫1次
 */
+ (void)load {

    Method m1 = class_getClassMethod(objc_getClass("UIImage"), @selector(imageNamed:));
    Method m2 = class_getClassMethod(objc_getClass("UIImage"), @selector(xfq_imageNamed:));
    method_exchangeImplementations(m1, m2);
}

+ (UIImage *)xfq_imageNamed:(NSString *)name {
    // 獲取當前裝置的系統版本號 
    float version = [[UIDevice currentDevice].systemVersion floatValue];
    // 判斷版本號,如果 >= 7.0,在圖片名後面拼接 "_ios7"
    if (version >= 7.0) {
        name = [name stringByAppendingString:@"_ios7"];
    }
    // 這裡需要特別注意: return的時候,使用的是自定義的方法,這個時候由於已經交換了方法,實際上呼叫的是系統的imageNamed方法'
    return [UIImage xfq_imageNamed:name];
}

// 注意: 在分類中重寫系統方法,不能滿足要求
// 這種方式會導致系統原來的方法無法使用
//+ (UIImage *)imageNamed:(NSString *)name {
//    
//    float version = [[UIDevice currentDevice].systemVersion floatValue];
//    if (version >= 7.0) {
//        name = [name stringByAppendingString:@"_ios7"];
//    }
//    // 會死迴圈
//    return [self imageNamed:name];
//}

@end

2> 控制器中呼叫

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end

@implementation ViewController

/**
 iOS6  -> iOS7
 擬物化 -> 扁平化
 */
- (void)viewDidLoad {
    [super viewDidLoad];
    // 正是因為交換了方法的實現,所以這裡的程式碼不用做任何修改,就可以實現想要的效果
    self.imageView.image = [UIImage imageNamed:@"open"];
}
@end

相關推薦

執行runtime-方法交換

1> 建立一個 Person 類,並定義兩個方法 study 和 run,分別實現 #import "Person.h" @implementation Person - (void)study { NSLog(@"study"); } -

Objective C執行runtime

前言: Objective C的runtime技術功能非常強大,能夠在執行時獲取並修改類的各種資訊,包括獲取方法列表、屬性列表、變數列表,修改方法、屬性,增加方法,屬性等等,本文對相關的幾個要點做了一個小結。 目錄:   (6) 總結 (1)在執行時對函式進行動態替換 : 

Objective C執行runtime技術的幾個要點總結

前言: Objective C的runtime技術功能非常強大,能夠在執行時獲取並修改類的各種資訊,包括獲取方法列表、屬性列表、變數列表,修改方法、屬性,增加方法,屬性等等,本文對相關的幾個要點做了一個小結。 目錄:   (6) 總結 (1)在執行時對函式進行動態替換 : cl

Java 執行RUNTIME註解詳解

整理測試後並附上完整程式碼 註解定義 註解(Annotation),也叫元資料。一種程式碼級別的說明。它是JDK1.5及以後版本引入的一個特性,與類、介面、列舉是在同一個層次。它可以宣告在包、類、欄位、方法、區域性變數、方法引數等的前面,用來對這些元

iOS執行runtime探究一:重要概念

iOS執行時簡介 因為Objc是一門動態語言,所以它總是想辦法把一些決定工作從編譯連線推遲到執行時。也就是說只有編譯器是不夠的,還需要一個執行時系統 (runtime system) 來執行編譯後的程式碼。這就是 Objective-C Runtime 系統存

Go 運行runtime

垃圾 .com map cgo 一個 也不會 bsp 部分 targe 盡管 Go 編譯器產生的是本地可執行代碼,這些代碼仍舊運行在 Go 的 runtime(這部分的代碼可以在 runtime 包中找到)當中。這個 runtime 類似 Java 和 .NET 語言所用到

Kubernetes容器執行CRI簡介

Kubernetes節點的底層由一個叫做“容器執行時”的軟體進行支撐,它負責比如啟停容器這樣的事情。最廣為人知的容器執行時當屬Docker,但它不是唯一的。事實上,容器執行時這個領域發展迅速。為了使Kubernetes的擴充套件變得更容易,我們一直在打磨支援容器

iOS學習筆記56Runtime-Objective-C Runtime 執行之三:方法與訊息

前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 SEL

執行許可權的處理方法以打電話為例 Api 23,24

Android中危險許可權共9組24個許可權 group:android.permission-group.CONTACTS permission:android.permission.WRITE_CONTACTS permission:android

剖析執行讓你看懂執行

init ont get tle pre art details ddc down 執行時機制:比較高級的特性,純C語言 實際上我們平時寫的OC代碼。都是轉成C語言的執行時代碼,執行時代碼的效率更高,更直接 Person.h @inter

一個類,有新增元素add和獲取元素數量size方法。 啟動兩個線程。線程1向容器中新增數據。線程2監聽容器元素數量,當容器元素數量為5,線程2輸出信息並終止

override tac trace add syn countdown print import 數據 方式一: /** * 兩個線程要是可見的所以要加上votalile */public class Test_01 { public static void

Java多執行java中的Sleep方法

點我跳過黑哥的卑鄙廣告行為,進入正文。 Java多執行緒系列更新中~   正式篇: Java多執行緒(一) 什麼是執行緒 Java多執行緒(二)關於多執行緒的CPU密集型和IO密集型這件事 Java多執行緒(三)如何建立執行緒 Java多執行緒(四)java中的Sleep方法  

Web應用啟動,後臺自動啟動一個執行

原文:http://blog.sina.com.cn/s/blog_6810dfc20101ipzq.html Web應用啟動時,後臺自動啟動一個執行緒   (1)前言     前幾天,manager問道一個問題:能不能實現類似於cro

java day25 多執行 單例類Runtime,Timer

25.01_多執行緒(單例設計模式)(掌握) 單例設計模式:保證類在記憶體中只有一個物件。 如何保證類在記憶體中只有一個物件呢? (1)控制類的建立,不讓其他類來建立本類的物件。private (2)在本類中定義一個本類的物件。Singl

執行join方法的簡單介紹:

1、join方法的實現原理: join方法原理就是利用執行緒的wait方法等待操作: A執行緒中呼叫了B執行緒的join方法,則相當於在A執行緒中呼叫了B執行緒的wait方法,當B執行緒執行完(或者

Java 多執行—— 執行緒的生命週期及方法

這篇部落格介紹執行緒的生命週期。   執行緒是一個動態執行的過程,它也有從建立到死亡的過程。 執行緒的幾種狀態 在 Thread 類中,有一個列舉內部類: 上面的資訊以圖片表示如下:   第一張圖:  第二張圖:把等待、計時等待、阻塞看成阻塞一個狀態了 1、新建狀態(ne

執行緒——停止執行結束run方法

package com.qianfeng.demo01; /** * 停止執行緒: * 1.stop():已過時,這種方法有固有的不安全性,強制停止執行緒,不論處於什麼狀態都會停止,就會導致執行緒

Unity在執行程式碼中設定材質的渲染模式RenderingMode

public enum RenderingMode { Opaque, Cutout, Fade, Transparent, } public static void SetMaterialRenderingMode (Material material, Render

[面試] C/C++ 語法—— RTTI執行型別資訊

RTTI(RunTime Type Information),顧名思義,物件執行時型別資訊,以便在執行時進行型別識別。 C++ 的物件識別可通過以下三個技術得以實現: (1)dynamic_cast 運算子(型別安全的向下轉型) 向下轉型是不安全的,多型

Objective-C Runtime 執行之三:方法與訊息

前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 SEL