Objective-c 初階 —— Runtime(方法交換 消息傳遞)

一、消息傳遞

1、什么是消息

[a func1];

我們會把這種用方括號來調函數的方式稱為發消息。對于這個例子,就相當于我們給 a 這個對象發了個 func1 的消息(個人認為指令更好理解)。

2、什么是 selector

selector 就是一個函數區分器。它只會給這個方法名一個唯一的哈希值。也就是說,如果只要兩個函數的方法名是一樣的,那么他們的 selector 的哈希值就是一樣的。

3、什么是 isa 指針

每個對象都有一個 isa 指針。

實例對象的?isa 指針指向的是該實例所屬的類對象,而類對象的 isa 指針指向元類對象。

那么如何區分類對象和元類對象呢?類對象存的是實例方法,不存類方法,而元類存的是類方法。

4、消息傳遞過程

1. 當一個方法要傳給一個實例對象,那么 runtime 系統就會通過這個實例對象的 isa 指針找到該對象屬于哪個類對象

2. 在這個類對象里的 dispatch table 找有沒有符合當前 selector 的函數實現

3. 如果有,直接調用。

4. 如果沒有,就不斷地沿著這個類對象的 superclass 指針一路沿著繼承鏈向上找,直到找到符合的函數實現或找到 NSObject 類。

5. 如果直到 NSObject 類都沒找到,就進入“消息轉發”的環節。

根據 selector 找對應的函數實現,runtime 做了一個小小的優化。就是給每個類對象一個緩存。這個緩存存的是在該類找過的實例方法實現和該類通過繼承得來的函數實現的地址。于是在找函數實現時,runtime 會先在這個類的緩存里找。如果沒找到才去這個類的 dispatch table 里找;再找不到就沿著繼承鏈往上找。

二、消息轉發的過程

1、什么是消息轉發

消息轉發就是當 runtime 在繼承鏈中找不到 selector 對應的函數實現后,就會進行消息轉發,即用其他對象來調這個方法。如果沒有其他類能成功調用這個方法,才會報錯。所以可以理解成消息轉發就是報錯前的最后一道防線。

2、消息轉發的過程

2.1. 動態方法解析(resolveInstanceMethod:)

+ (BOOL)resolveInstanceMethod:(SEL)selector //實例對象的動態方法解析調+ (BOOL)resolveClassMethod:(SEL)selector //類對象的動態方法解析調
@implementation Person// 動態方法解析入口:當找不到實例方法 sayHello 時會調用這個方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {if (sel == @selector(sayHello)) {// 使用 class_addMethod 動態添加方法實現class_addMethod(self, sel, (IMP)dynamicSayHello, "v@:");return YES;}return [super resolveInstanceMethod:sel];
}// 動態添加的方法實現
void dynamicSayHello(id self, SEL _cmd) {NSLog(@"Hello from dynamic method!");
}@end

?其中 selector 是未處理的方法。?返回值表示能否新增一個方法來處理。如果可以,返回 YES;否則就看看基類能不能處理這個 selector。

2.2. 備用接收者

- (id)forwardingTargetForSelector:(SEL)aSelector;
// 備用接收者類
@interface BackupHandler : NSObject
- (void)sayHello;
@end@implementation BackupHandler
- (void)sayHello {NSLog(@"👉 BackupHandler 收到了 sayHello 消息!");
}
@end// 原始類:沒有實現 sayHello,但可以轉發給 backup
@interface MainObject : NSObject
@property (nonatomic, strong) BackupHandler *backup;
@end@implementation MainObject// 快速消息轉發:返回備用接收者
- (id)forwardingTargetForSelector:(SEL)aSelector {if (aSelector == @selector(sayHello)) {return self.backup; // 轉發給備用對象}return [super forwardingTargetForSelector:aSelector];
}@end

?這里 selector 也是未處理的方法。返回值為當前找到的備援接受者,如果沒有則返回nil,進入下一階段。

2.3. 完整消息轉發

- (void)forwardInvocation:(NSInvocation *)anInvocation;
// 目標處理者類
@interface RealHandler : NSObject
- (void)sayHello;
@end@implementation RealHandler
- (void)sayHello {NSLog(@"? RealHandler 處理了 sayHello 方法!");
}
@end// 原始類:完全不實現 sayHello
@interface MainObject : NSObject
@property (nonatomic, strong) RealHandler *handler;
@end@implementation MainObject// 第一步:提供方法簽名,告訴 runtime 方法是怎樣的
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {if (aSelector == @selector(sayHello)) {// v@: → 返回 void, 參數是 self 和 _cmdreturn [NSMethodSignature signatureWithObjCTypes:"v@:"];}return [super methodSignatureForSelector:aSelector];
}// 第二步:收到完整調用對象,自己決定怎么處理
- (void)forwardInvocation:(NSInvocation *)anInvocation {SEL sel = [anInvocation selector];if ([self.handler respondsToSelector:sel]) {[anInvocation invokeWithTarget:self.handler]; // 手動轉發} else {[super forwardInvocation:anInvocation]; // 沒法處理就崩潰}
}@end

?其中 anInvocation 里面有原來消息的接收者、selector?、全部實參、返回值。

2.4. 報錯中斷

三、方法交換

1、dispatch table

每個類結構都包括以下兩個基本元素:指向基類的指針 & dispatch table。其中 dispatch table 就是一個 2 列的函數表,左邊是某個函數的?selector,右邊是這個函數的具體實現的地址。?

2、方法交換

本質就是把 dispatch table 里的兩個 address 的值交換。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91888.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91888.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91888.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【計算機網絡架構】樹型架構簡介

引言在當今數字化時代,網絡架構如同復雜的神經系統,支撐著各種信息的流通與交互。從個人日常的網絡瀏覽、在線購物,到企業的遠程辦公、數據存儲,再到國家層面的政務信息化、智慧城市建設,網絡架構都扮演著不可或缺的角…

llama-factory快速開始

llama-factory快速開始 文章目錄llama-factory快速開始前言一、環境配置1.1 訓練順利運行需要包含4個必備條件1.2 llama-factory下載1.3 環境下載1.4 硬件環境校驗二、啟動前言 https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md這是GitHub中文介紹文檔&#…

408數據結構強化(自用)

常用代碼片段&#xff08;持續更新&#xff09;折半查找void SearchBinary(int A[];int x){int low 0, high n-1, mid;while(low<high){mid (lowhigh)/2;if(A[mid]x) break;else if(A[mid] < x) low mid 1;else high mid - 1;}順序表逆置void Reverse(SqList &…

linux cpu頻率和AVS調壓等級

1&#xff0c;linux常見的cpu頻率對應的電壓等級對應參數表如下:頻率&#xff08;GHz&#xff09;電壓&#xff08;V&#xff09;1.61.41.41.21.21.01.00.82&#xff0c;avs調壓的幾種方式linux內核宏解釋Linux內核中&#xff0c;AVS調壓的實現依賴于一些宏定義和配置選項&…

Input輸入和Screen相關

知識點using System.Collections; using System.Collections.Generic; using UnityEngine;public class Lesson11 : MonoBehaviour {// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){#region 注意&#xff0c…

如何在CSDN變現?如何賺錢?如何漲粉?如何找到優質大V博主合作伙伴?

&#x1f525; 2025最新 如何在CSDN變現&#xff1f;如何賺錢&#xff1f;如何跟對人&#xff1f;如何找到優質博主合作伙伴&#xff1f; 大家好&#xff0c;我是貓頭虎&#xff0c;今天??想和大家聊聊在CSDN平臺變現的問題。這也是絕大多數伙伴非常關心的一個話題——其實&…

OpenCV特征點提取算法orb、surf、sift對比

下面是 OpenCV 中三種常用特征點提取算法&#xff1a;ORB、SURF 和 SIFT 的詳細對比&#xff0c;從 算法原理、性能、使用限制 和 適用場景 多維度進行總結&#xff0c;幫助大家在實際項目中合理選擇。一覽表&#xff1a;ORB vs. SURF vs. SIFT屬性/算法ORBSURFSIFT全稱Oriente…

LeafletJS 與 React:構建現代地圖應用

引言 LeafletJS 是一個輕量、靈活的 JavaScript 地圖庫&#xff0c;廣泛用于創建交互式 Web 地圖&#xff0c;而 React 作為現代前端框架&#xff0c;以其組件化、狀態管理和虛擬 DOM 特性&#xff0c;成為構建動態用戶界面的首選工具。將 LeafletJS 與 React 結合&#xff0c…

前后端數據交互,關于表單數據傳輸問題

表單提交var formData new FormData(); // 添加每個事故ID作為單獨的參數 accidentIds.forEach(id > formData.append(accidentIds, id)); formData.append(status, statusText); $.messager.confirm(確認, 確定要將事故記錄標記為 statusText 嗎&#xff1f;, function …

新書推介 | 吉林大學出版教材《汽車智能輔助駕駛系統技術》,國產仿真工具鏈GCKontrol-GCAir教學應用

近日&#xff0c;吉林大學出版了由高鎮海教授、孫天駿副教授主編的新教材《汽車智能輔助駕駛系統技術》&#xff0c;本書系統地介紹了汽車智能輔助駕駛系統的發展需求、物理架構、功能算法、技術原理以及應用場景。在教材第17章《仿真測試》&#xff0c;應用國產化GCKontrol-GC…

從 0 到 1 玩轉 XSS - haozi 靶場:環境搭建 + 全關卡漏洞解析

文章目錄前言靶場地址0X00 直接注入0X01 閉合標簽10X02 閉合標簽20X03 繞過特殊符號10X04 繞過特殊符號20X05 繞過注釋符0X06 繞過更多符號0X07 繞過更多符號20X08 繞過閉合符號0X09 繞過URL匹配0X0A 繞過URL過濾0X0B 繞過大寫轉換10X0C 繞過大寫轉換20X0D 繞過注釋0X0E 古英語…

TF卡格式化

cmd 輸入diskpart,在新打開的窗口輸入list disk&#xff0c;然后select disk [磁盤號]&#xff0c;clean&#xff0c;回車變成未分區的。再選中磁盤&#xff0c;選中之后create partition [分區名] 回車&#xff0c;list partition&#xff0c;查看分區&#xff0c;輸入active&…

Python爬蟲實戰:研究sqlparse庫相關技術

1. 引言 1.1 研究背景與意義 在當今數據驅動的時代,SQL 作為關系型數據庫的標準查詢語言,被廣泛應用于各種數據處理和分析場景。隨著數據庫應用的不斷發展,SQL 代碼的規模和復雜度也在不斷增加,這給 SQL 代碼的編寫、維護和優化帶來了挑戰。 研究表明,低效的 SQL 查詢是…

全球天氣預報5天(經緯度版)免費API接口教程

本文全面介紹由接口盒子免費API提供的全球天氣預報API&#xff0c;支持通過經緯度坐標獲取任意地區未來5天的詳細天氣預報數據。 一、接口核心功能 ?全球覆蓋?&#xff1a;支持全球任意經緯度坐標點的天氣預報?高精度預報?&#xff1a;提供每3小時為間隔的精細化預報&…

5 基于STM32單片機的絕緣檢測系統設計(STM32代碼編寫+手機APP設計+PCB設計+Proteus仿真)

系列文章目錄 文章目錄 系列文章目錄前言1 1 資料獲取與演示視頻1.1 資料介紹1.2 資料獲取1.3 演示視頻 2 系統框架3 硬件3.1 主控制器3.2 顯示屏3.3 WIFI模塊3.4 DHT11溫濕度傳感器3.5 可調電位器 4 設計PCB4.1 安裝下載立創EDA專業版4.2 畫原理圖4.3 擺放元器件&#xff0c;設…

CPP學習之list使用及模擬實現

一、list簡介及用法 1. list簡介 list是可以在常數范圍內任意位置進行插入、刪除、修改操作的有順序性的容器&#xff0c;而且支持雙向迭代&#xff0c;其底層是雙鏈表結構&#xff0c;邏輯上連續但物理空間上不連續&#xff0c;只能通過指針來進行元素訪問&#xff0c;無法使用…

Spring Boot 參數校驗:@Valid 與 @Validated

在日常開發中&#xff0c;參數校驗是保障接口健壯性與數據安全的第一道防線。Spring Boot 為我們提供了基于 JSR-303/JSR-380 的強大校驗機制&#xff0c;通過注解與 AOP 實現了靈活且高效的數據校驗方式。本篇博客將詳細介紹 Spring Boot 中 Valid、Validated 注解的使用方法&…

linux看門狗重啟定位思路總結

1&#xff0c;看門狗定位思路&#xff08;1&#xff09;是否是死鎖導致查看日志查看是否有RCU install或者deadlock相關打印&#xff0c;如果有的話可以考慮使用lockdep死鎖檢測工具&#xff08;2&#xff09;中斷風暴查看中斷&#xff0c;抓中斷打印&#xff0c;可以查看/proc…

基于單片機直流電機測速中文液晶顯示設計

摘 要 在現在工業自動化高度發展的時期&#xff0c;幾乎所有的工業設備都離不開旋轉設備&#xff0c;形形色色的電機在不同領域發揮著很重要的作用。不同場合對電機控制要求是不同的&#xff0c;但大部分都會涉及到旋轉設備的轉速測量&#xff0c;從而利用轉速來實施對旋轉設備…

c# sqlsugar 主子表明細 查詢

在使用 SqlSugar ORM 進行數據庫操作時&#xff0c;特別是在處理主子表關系時&#xff0c;通常需要執行關聯查詢來獲取主表和其子表的數據。SqlSugar 提供了強大的查詢能力&#xff0c;支持多種方式的關聯查詢&#xff0c;包括左連接&#xff08;Left Join&#xff09;、內連接…