「iOS」————繼承鏈與對象的結構

iOS學習

  • 前言
  • 對象的底層結構
    • isa的類型isa_t
    • objc_class & objc_object
      • 類信息的靜態與動態存儲(ro、rw、rwe機制)
      • cache
      • bits
  • 繼承鏈
  • isKindOfClass和isMemberOfClass
      • `isKindOfClass:`
      • `isMemberofClass`


前言

對 對象底層結構的相關信息有點遺忘,簡略記錄一下。順便記錄一下繼承鏈相關。

對象的底層結構

isa指針采用了典型的適配器設計模式。
適配器設計模式(即將底層接口適配為客戶端需要的接口),達成上下層接口隔離的目的。

  • 上層OC對象 只需要通過 isa、Class、objc_object、objc_class 等接口訪問對象和類信息。 底層實現
  • 通過聯合體、結構體、位域等方式,封裝了復雜的內存布局和數據結構。
  • 適配器(如isa_t、objc_object、objc_class、cache_t、class_rw_t等)把底層復雜的數據結構和操作,適配成了上層易用的接口,實現了“接口隔離”和“解耦”。

isa的類型isa_t

union isa_t { //聯合體isa_t() { }isa_t(uintptr_t value) : bits(value) { }//提供了cls 和 bits ,兩者是互斥關系,即通過cls初始化,bits無默認值,通過bits初始化,cls無默認值Class cls;uintptr_t bits;
#if defined(ISA_BITFIELD)struct {ISA_BITFIELD;  // defined in isa.h  結構體定義的位域,儲存類信息和其他信息。};
#endif
};

位域如下:

isa存儲情況

  • nonpointer有兩個值,表示自定義的類等,占1
    • 0純isa指針
    • 1:不只是類對象地址,isa中包含了類信息、對象的引用計數
  • has_assoc表示關聯對象標志位,占1
    • 0沒有關聯對象
    • 1存在關聯對象
  • has_cxx_dtor 表示該對象是否有C++/OC的析構器(類似于dealloc),占1
    • 如果析構函數,則需要做析構邏輯
    • 如果沒有,則可以更快的釋放對象
  • shiftcls表示存儲類的指針的值(類的地址), 即類信息
    • arm64中占 33位,開啟指針優化的情況下,在arm64架構中有33位用來存儲類指針
    • x86_64中占 44
  • magic 用于調試器判斷當前對象是真的對象 還是 沒有初始化的空間,占6
  • weakly_refrenced是 指對象是否被指向 或者 曾經指向一個ARC的弱變量
    • 沒有弱引用的對象可以更快釋放
  • deallocating 標志對象是是否正在釋放內存
  • has_sidetable_rc表示 當對象引用計數大于10時,則需要借用該變量存儲進位
  • extra_rc(額外的引用計數) ,表示該對象的引用計數值,實際上是引用計數值減1
    • 如果對象的引用計數為10,那么extra_rc為9(這個僅為舉例說明),實際上iPhone 真機上的 extra_rc 是使用 19位來存儲引用計數的

clsisa 關聯原理就是isa指針中的shiftcls位域中存儲了類信息,其中initInstanceIsa的過程是將 calloc 指針 和當前的 類cls 關聯起來。

objc_class & objc_object

所有Class都是以objc_class為模版繼承而來的。isa指針的類型是Class,由objc_class定義的類型。

而結構體類型objc_class繼承自objc_object。obje_object是一個結構體,且有一個isa屬性,因此objc_class也擁有isa屬性

NSObject中的isa在底層是由Class 定義的,其中class的底層編碼來自 objc_class類型,所以NSObject也擁有了isa屬性

總結

  • 所有的對象 + + 元類 都有isa屬性
  • 所有的對象都是由objc_object繼承來的,類繼承自objc_class
  • 簡單概括就是萬物皆對象,萬物皆來源于objc_object,有以下兩點結論:
    • 所有以 objc_object為模板 創建的對象,都有isa屬性
    • 所有以objc_class為模板,創建的,都有isa屬性
  • 在結構層面可以通俗的理解為上層OC底層對接
    • 下層是通過 結構體 定義的 模板,例如objc_class、objc_object
    • 上層 是通過底層的模板創建的 一些類型,例如CJLPerson
      請添加圖片描述

objc_class的定義:

struct objc_class : objc_object {// Class ISA; //8字節Class superclass; //Class 類型 8字節cache_t cache;             // formerly cache pointer and vtableclass_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
}
  • isa屬性:繼承自objc_objectisa,占 8字節

  • superclass 屬性:Class類型,Class是由objc_object定義的,是一個指針,占8字節

  • cache屬性:簡單從類型class_data_bits_t目前無法得知,而class_data_bits_t是一個結構體類型,結構體內存大小需要根據內部的屬性來確定,而結構體指針才是8字節

  • bits屬性:只有首地址經過上面3個屬性的內存大小總和的平移,才能獲取到bits

類信息的靜態與動態存儲(ro、rw、rwe機制)

初始時,只有ro

當需要修改類信息的時候,rw引用ro,并拷貝一部分信息。

將需要動態更新的部分提取出來,存?rwe:

image-20220506113406159

總結:程序加載時方法存在ro。當類第一次使用的時候,rw就會引用ro;如果動態修改,就會從ro拷貝到rwe;修改的時候也是去操作rwe

rw和ro的區別ro放在純凈的內存空間(clean memory),是只讀的。rw在運行生成,存放在可以讀寫的內存空間中(dirty memory),一經使用,ro就會成為rw的一部分(通過指針引用)。并且rw對于真正需要修改的內容,還會拆分出class_rw_ext_t;簡稱rwe

cache

其中,cache類的內存大小為12+2+2=16字節。分別有:buckets(8字節),mask(4字節)或者_maskAndBuckets(8字節), _mask_unused(4字節) 加上 _flag(2字節), _occupied(2字節)。

注意:buckets是方法緩存中的一個哈希表數組,儲存了SEL和IMP。而mask使用來計算哈希索引的。這兩個可以快速定位方法緩存。

img

sel-imp是在cache_t_buckets屬性中,而在cache_t結構體中提供了獲取_buckets屬性的方法buckets()

我們可以通過相應的獲取方法sel() 以及 imp(pClass)獲得對應的sel-imp

bits

類的首地址平移32字節即可得到bits,bits儲存信息的類型是class_rw_t,其中可以獲取屬性列表和方法列表

請添加圖片描述

通過由class_rw_t提供的propertoes方法,可以獲取到一個實際類型property_array_t的變量,其中有一個list的類型是property_list_t,是一個指針,存儲了 property_list,即屬性列表。所以bits中儲存了屬性列表。

通過由class_rw_t提供methods方法, 可以獲取到一個實際類型method_array_t的變量,其中的list指針,類型是method_list_t,里面就是具體的方法列表。注意,該列表里面只有實例方法。類方法存儲在元類的bits屬性中,獲取方法與該方法相同,畢竟類是元類的實例。

在class_rw_t中,還有一個ro方法,其返回類型是class_ro_t,其中有一個類型為ivar_list_tivars屬性,其中儲存著成員變量列表。該成員變量列表不僅儲存著{}定義的成員變量,還存儲著屬性定義的成員變量。

class_rw_t中的相關方法

繼承鏈

首先是最經典的圖片:
請添加圖片描述

  • isa走位

    isa的走向有以下幾點說明:

    • 實例對象(Instance of Subclass)isa 指向 類(class)
    • 類對象(class) isa 指向 元類(Meta class)
    • 元類(Meta class)isa 指向 根元類(Root metal class)
    • 根元類(Root metal class)isa 指向它自己本身,形成閉環,這里的根元類就是NSObject

    superclass走位

    superclass(即繼承關系)的走向也有以下幾點說明:

    • 類之間的繼承關系

      • 類(subClass) 繼承自 父類(superClass)
      • 父類(superClass) 繼承自 根類(RootClass),此時的根類是指NSObject
      • 根類 繼承自 nil,所以根類NSObject可以理解為萬物起源,即無中生有
    • 元類也存在繼承,元類之間的繼承關系如下:

      • 子類的元類(metal SubClass) 繼承自 父類的元類(metal SuperClass)

      • 父類的元類(metal SuperClass) 繼承自 根元類(Root metal Class

      • 根元類(Root metal Class) 繼承于 根類(Root class),此時的根類是指NSObject

    • 【注意】實例對象之間沒有繼承關系之間有繼承關系

isKindOfClass和isMemberOfClass

isKindOfClass:

  • 一切皆從調用者obj的isa開始,然后順著superclass走下去,直到找到cls或superclass為nil結束
  • 當superclass為nil,意味著最后的根類NSObject也不是cls,返回flase。

類調用

判斷順序: SubClass -> MetaClass->MetaClass->...->RootMetaClass->NSObject

其中, 類對象調用方法的本質 是判斷 cls 是不是 元類的繼承鏈 上的任意一個

元類調用

MetaClassISA 指向 RootMetaClass ,所以從 RootMetaClass 開始比較判斷是不是我們傳入的cls,如果不是,再看根類NSObject是不是,如果NSObject也不是,就徹底沒有了,返回false,

img

根元類的父類是NSObject

cls判斷順序如圖:MetaClass -> RootMetaClass->NSObject

**對象調用:**cls判斷順序如圖所示:object -> SubClass -> SubClass ->...->NSObject

本質是判斷 cls 是不是 類繼承鏈 上的任意一個

isMemberofClass

不用像isKindOfClass循環直到找到或nil,他只要比較cls是不是我當前的isa指向,是返回true,不是返回false。

這個方法單純地用來判斷,cls是不是調用者的isa !!

類對象調用

傳入任何類對象都是false,因為類的isa指向元類

元類對象調用

元類的isa指向根元類NSObjcet,傳入任何類對象也都是false

對象調用:

只要判斷對象的isa,也就是圖中的SubClass是不是我們傳入的cls

  1. 只判斷自己的類對象是不是傳入的cls
  2. 只接受類對象傳入 ,因為沒有isa,不存在元類的介入

總結
isMemberOfClass

  • 對象調用:判斷對象的isa(類對象)是否等于傳入的cls,只判斷本類,不查父類。

    • 查詢鏈:對象 → isa(類對象)== cls ?
  • 類對象調用:判斷類對象的isa(元類)是否等于cls。

    • 查詢鏈:類對象 → isa(元類)== cls ?
  • 元類對象調用:判斷元類對象的isa(根元類)是否等于cls。

    • 查詢鏈:元類對象 → isa(根元類)== cls ?

isKindOfClass

  • 對象調用:判斷對象的isa(類對象)是否等于cls,不等則沿superclass鏈查找父類,直到NSObject或nil。

    • 查詢鏈:對象 → isa(類對象)→ superclass → … → NSObject → nil
  • 類對象調用:判斷類對象的isa(元類)及其superclass鏈是否等于cls,最終會查到NSObject。

    • 查詢鏈:類對象 → isa(元類)→ superclass(父類元類)→ … → 根元類 → superclass(NSObject類對象)→ nil
  • 元類對象調用:判斷元類對象的isa(根元類)及其superclass鏈是否等于cls,最終會查到NSObject類對象。

    • 查詢鏈:元類對象 → isa(根元類)→ superclass(NSObject類對象)→ nil

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

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

相關文章

代碼隨想錄day46dp13

647. 回文子串 題目鏈接 文章講解 回溯法 class Solution { public:int count 0;// 檢查字符串是否是回文bool isPalindrome(string& s, int start, int end) {while (start < end) {if (s[start] ! s[end]) return false;start;end--;}return true;}// 回溯法&#…

學習隨筆錄

#61 學習隨筆錄 今日的思考 &#xff1a; 反思一下學習效率低下 不自律 或者 惰性思維 懶得思考 又或者 好高婺遠 頂級自律從不靠任何意志力&#xff0c;而在于「平靜如水的野心」_嗶哩嗶哩_bilibili 然后上面是心靈雞湯合集 vlog #79&#xff5c;程序員遠程辦公的一天…

python-函數進階、容器通用方法、字符串比大小(筆記)

python數據容器的通用方法#記住排序后容器類型會變成list容器列表 list[1,3,5,4,6,7] newListsorted(list,reverseTrue) print(newList) [7, 6, 5, 4, 3, 1]list[1,3,5,4,6,7] newListsorted(list,reverseFalse) print(newList) [1, 3, 4, 5, 6, 7]字典排序的是字典的key字符串…

關閉chrome自帶的跨域限制,簡化本地開發

在開發時為了圖方便,簡化本地開發,懶得去后端配置允許跨域,那就可以用此方法1. 右鍵桌面上的Chrome瀏覽器圖標&#xff0c;選擇“創建快捷方式”到桌面。2. 在新創建的快捷方式的圖標上右鍵&#xff0c;選擇“屬性”。3. 在彈出窗口中的“目標”欄中追加&#xff1a; --allow-r…

C++___快速入門(上)

第一個C程序#include<iostream> using namespace std; int main() {cout << "hello world !" << endl;return 0; }上邊的代碼就是用來打印字符串 “hello world !” 的&#xff0c;可見&#xff0c;與C語言還是有很大的差別的&#xff0c;接下來我…

構建企業級Docker日志驅動:將容器日志無縫發送到騰訊云CLS

源碼地址:https://github.com/k8scat/docker-log-driver-tencent-cls 在現代云原生架構中,容器化應用已經成為主流部署方式。隨著容器數量的快速增長,如何高效地收集、存儲和分析容器日志成為了一個關鍵挑戰。傳統的日志收集方式往往存在以下問題: 日志分散在各個容器中,難…

Kafka——消費者組重平衡能避免嗎?

引言 其實在消費者組到底是什么&#xff1f;中&#xff0c;我們講過重平衡&#xff0c;也就是Rebalance&#xff0c;現在先來回顧一下這個概念的原理和用途。它是Kafka實現消費者組&#xff08;Consumer Group&#xff09;彈性伸縮和容錯能力的核心機制&#xff0c;卻也常常成…

使用爬蟲獲取游戲的iframe地址

如何通過爬蟲獲取游戲的iframe地址要獲取網頁中嵌入的游戲的iframe地址&#xff08;即iframe元素的src屬性&#xff09;&#xff0c;您可以使用網絡爬蟲技術。iframe是HTML元素&#xff0c;用于在當前頁面中嵌入另一個文檔&#xff08;如游戲頁面&#xff09;&#xff0c;其地址…

NTLite Ent Version

NTLite是一款專業的系統安裝鏡像制作工具&#xff0c;通過這款軟件可以幫助用戶快速生成鏡像文件打好補丁&#xff0c;很多朋友在安裝電腦系統的時候一般都安裝了windows系統的所有Windows組件&#xff0c;其實有很多Windows組件你可能都用到不到&#xff0c;不如在安裝系統時就…

Maven之依賴管理

Maven之依賴管理一、Maven依賴管理的核心價值二、依賴的基本配置&#xff08;坐標與范圍&#xff09;2.1 依賴坐標&#xff08;GAV&#xff09;2.2 依賴范圍&#xff08;scope&#xff09;示例&#xff1a;常用依賴范圍配置三、依賴傳遞與沖突解決3.1 依賴傳遞性示例&#xff1…

【Unity實戰100例】Unity資源下載系統開發流程詳解(移動端、PC端 ,局域網控制臺服務)

目錄 一、項目概述 二、服務器開發 1、配置文件設計 1、加載配置 2. 處理客戶端請求 3. 文件下載處理 三、客戶端開發 1、配置管理 1、配置加載與保存 2、下載任務管理 1、任務類設計 2、下載隊列管理 3、核心下載流程 四、UI系統實現 五、部署與測試 1、服務…

[Python] -進階理解7- Python中的內存管理機制簡析

Python(尤其是 CPython)采用自動內存管理機制,核心包括引用計數(Reference Counting)與垃圾回收機制(Garbage Collection),并配合專門的內存池和分配器機制來提升效率與減少碎片。 這套機制隱藏在開發者視線之外,Python 開發者無需手動申請或釋放內存。 二、Python 內…

云祺容災備份系統AWS S3對象存儲備份與恢復實操手冊

1、創建密鑰訪問AWS控制臺&#xff0c;鼠標移至右上角賬戶處&#xff0c;在彈出菜單中點擊安全憑證&#xff0c;如圖1。圖1在彈出頁面中&#xff0c;下滑找到訪問密鑰&#xff0c;并點擊創建訪問密鑰&#xff0c;如圖2。圖2選擇其他&#xff0c;并點擊下一步&#xff0c;如圖3。…

使用 LLaMA 3 8B 微調一個 Reward Model:從入門到實踐

本文將介紹如何基于 Meta 的 LLaMA 3 8B 模型構建并微調一個 Reward Model&#xff0c;它是構建 RLHF&#xff08;基于人類反饋的強化學習&#xff09;系統中的關鍵一環。我們將使用 Hugging Face 的 transformers、trl 和 peft 等庫&#xff0c;通過參數高效微調&#xff08;L…

matrix-breakout-2-morpheus靶場攻略

靶場使用將壓縮包解壓到一個文件夾中&#xff0c;用虛擬機應用新建虛擬機&#xff0c;掃描虛擬機&#xff0c;掃描那個文件夾&#xff0c;就可以把虛擬機掃出來了&#xff0c;然后啟動虛擬機這時候靶場啟動后&#xff0c;咱們現在要找到這個靶場。靶場是網頁形式的&#xff0c;…

MySQL 復制表

MySQL 復制表 概述 在數據庫管理中&#xff0c;復制表是一項常用的操作。它允許數據庫管理員將一個表中的數據復制到另一個表中&#xff0c;無論是同一個數據庫還是不同的數據庫。MySQL數據庫提供了多種方法來復制表&#xff0c;本文將詳細介紹MySQL復制表的過程、方法及其應用…

『哈哥贈書 - 55期』-『碼農職場:IT人求職就業手冊』

文章目錄?? 碼農職場&#xff1a;IT人求職就業手冊?? 本書簡介?? 作者簡介?? 編輯推薦這是一本專為廣大IT行業求職者量身定制的指南&#xff0c;提供了從職前準備到成功就業的全方位指導&#xff0c;涵蓋了職業目標規劃、自我技能評估、求職策略、簡歷準備以及職場心理…

單片機學習課程

單片機學習課程 課程介紹 單片機技術作為現代工業自動化、電子電氣、通信及物聯網等領域的主流技術&#xff0c;早已深度融入我們生活與生產的各個角落。從常見家電到自動化公共設施&#xff0c;都離不開單片機的支持。同時&#xff0c;它也是學習 ARM 嵌入式系統、FPGA 設計等…

【AcWing 143題解】最大異或對

AcWing 143. 最大異或對 【題目描述】 在查看解析之前&#xff0c;先給自己一點時間思考哦&#xff01; 【題解】 本題要求給定一個整數序列&#xff0c;找出其中任意兩個數進行異或運算后&#xff0c;結果的最大值是多少。由于數據規模較大&#xff0c;我們不能簡單地通過兩…

SQLAlchemy 2.0簡單使用

記錄一下SQLAlchemy 2.0連接mysql數據庫的方法及簡單使用 環境及依賴 Python:3.8 mysql:8.3 Flask:3.0.3 SQLAlchemy:2.0.37 PyMySQL:1.1.1使用步驟 1、創建引擎&#xff0c;鏈接到mysql engine create_engine(mysqlpymysql://{username}:{password}{ip}:3306/{database_name}…