【iOS】類結構分析

前言

之前我們已經探索得出對象的本質就是一個帶有isa指針的結構體,這篇文章來分析一下類的結構以及類的底層原理。

類的本質

類的本質

我們在main函數中寫入以上代碼,然后利用clang對其進行反編譯,可以得到c++文件

可以看到底層使用Class接收,接下來找到Class的定義

發現Class在底層定義為一個名為objc_class的結構體

查找objc_class,發現它繼承自objc_object

可以得出:類的本質是objc_class類型的結構體,objc_class繼承自objc_object,因此可以一句話概括——萬物皆對象

objc_class&objc_object、objc&NSObject的關系

objc_object和NSObject

為什么說繼承自objc_object就滿足萬物皆對象?

我們看到NSObject的定義

對比objc_object的定義:

仔細比較可以看出:

  • 其實NSObject是objc_object的仿寫,和objc_object的定義是一樣的,在底層會編譯成objc_object

  • 同理NSObject類是OC版本的objc_class

而之前我們學習過的NSObject_IMPL則是NSObject編譯到objc_object的中間產物,并且實例偽繼承自NSObject_IMPL,正如繼承objc_object的皆為對象。

objc_class&objc_object

從上文我們已經得知:objc_class繼承自objc_object,我們尋找objc_object的定義

可以找到兩個定義:第一個位于objc.h,沒有被廢除,從編譯的main-arm64.cpp中可以看到,使用的這個版本的objc_object。第二個位于objc-privat.h

總結objc_class與objc_object的關系如下:

  • 結構體類型objc_class繼承自objc_object類型,其中objc_object也是一個結構體,且有一個isa屬性,所以objc_class也擁有了isa屬性

  • mian-arm64.cpp底層編譯文件中,NSObject中的isa在底層是由Class 定義的,其中class的底層編碼來自 objc_class類型,所以NSObject也擁有了isa屬性

  • NSObject是一個類,用它初始化一個實例對象objc,objc 滿足objc_object的特性(即有isa屬性),主要是因為isa 是由 NSObject 從objc_class繼承過來的,而objc_class繼承自objc_object,objc_object 有isa屬性。所以對象都有一個isa,isa表示指向,來自于當前的objc_object

  • objc_object(結構體)是當前的根對象,所有的對象都有這樣一個特性objc_object,即擁有isa屬性

objc_object 與 對象的關系

  • 所有的對象都是以 objc_object 為模板繼承過來的

  • 所有的對象是來自 NSObject(OC),但是真正到底層的是一個objc_object(C/C++)的結構體類型

  • objc_object對象的關系 是 繼承關系

總結

所有的對象 + 類 + 元類 都有isa屬性

所有的對象都是由objc_object繼承來的

簡單概括就是萬物皆對象,萬物皆來源于objc_object,有以下兩點結論:

  • 所有以 objc_object為模板創建的對象,都有isa屬性

  • 所有以 objc_class為模板創建的類,都有isa屬性

在結構層面可以通俗的理解為上層OC與底層的對接:

  • 下層是通過結構體定義的模板,例如objc_class、objc_object

  • 上層是通過底層的模板創建的一些類型,例如TCJPerson

objc_class、objc_object、isa、object、NSObject等的整體的關系,如下圖:

類的結構

從objc_class的定義可以得出,類有4個屬性:

  • Class ISA:類對象與實例對象一樣,同樣有isa指針,類對象的isa指針關聯著元類,Class本身就是一個指針,占用8字節(這個屬性是繼承自objc_object的)

  • Class superclass:即類的父類,Class類型,占用8個字節

  • cache_t cache

cache_t是一個結構體,內存長度由所有元素決定:_bucketsAndMaybeMask是long類型,它是一個指針,占用8字節; mask_t是個uint32_t類型,_mask占用4字節;因_occupied和_flags都是uint16_t類型,uint16_t是 unsigned short 的別名,所以_occupied占用2字節;flags占用2字節=>cache_t占用16字節。這個屬性其實是用來保存方法緩存的,后續博客中會詳細介紹。

  • class_data_bits_t bits

class_data_bits_t bits

class_data_bits_t bits這個屬性用來存數據,類的屬性和方法就保存在這里。可以看到objc_class中有一個class_rw_t *data()方法。

class_rw_t是在運行時生成的,它在realizeClass中生成,它包含了class_ro_t.它在_objc_init方法中關于dyld的回調的map_images中最終將分類的方法與協議都插入到自己的方法列表、協議列表中.它不包含成員變量列表,因為成員變量列表是在編譯期就確定好的,它只保存在class_ro_t中.不過,class_rw_t中包含了一個指向class_ro_t的指針

類的屬性方法

類的屬性

通過LLDB調試我們可以發現,bits當中存儲的信息類型是class_rw_t,是一個結構體類型,在這個結構體中有提供相應的方法去獲取屬性列表、方法列表等。

通過LLDB進一步調試可以發現,這個屬性列表中只有屬性,沒有成員變量。屬性與成員變量的區別就是有沒有set、get方法,如果有,則是屬性,如果沒有,則是成員變量。

除此之外,class_rw_t中有個屬性class_ro_t,class_ro_t是在編譯期生成的,它存儲了當前類在編譯期就已經確定的屬性、方法以及協議,它里面沒有分類中定義的方法和協議。而成員變量就存放在ro的ivars里面

總結如下:

  • 通過{}定義的成員變量,會存儲在類的bits屬性中,通過bits --> data() -->ro() --> ivars獲取成員變量列表,除了包括成員變量,還包括屬性定義的成員變量

  • 通過@property定義的屬性,也會存儲在bits屬性中,通過bits --> data() --> properties() --> list獲取屬性列表,其中只包含屬性

類的方法

類的實例方法存儲在類的bits屬性中,通過bits --> methods() --> list獲取實例方法列表,參觀游客實例方法,方法列表中還包含屬性的set方法和get方法,以及系統在底層添加的C++的.cxx_destruct方法。

類的類方法存儲在元類的bits屬性中,通過元類bits --> methods() --> list獲取類方法列表。

結論

  • 成員變量存放在ivar

  • 屬性存放在property,同時也會存一份在ivar,并生成setter、getter方法

  • 對象方法存放在類里面

  • 類方法存放在元類里面

補充

類存在幾份

由于類的信息在內存中永遠只存在一份,所以 類對象只有一份。

isKindOfClass和isMerberOfClass的理解

對于isMerberOfClass,方法會對比元類或類本身與某個類(元類還是類取決于類方法還是實例方法,總之就是取isa指針指向的東西)

而對于isKindOfClass,走以下邏輯:

最后給出一張isa的走位圖,實現為superclass指向,虛線為isa指向

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

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

相關文章

Vanna.AI:解鎖連表查詢的新境界

Vanna.AI:解鎖連表查詢的新境界 在當今數字化時代,數據已成為企業決策的核心驅動力。然而,從海量數據中提取有價值的信息并非易事,尤其是當數據分散在多個表中時,連表查詢成為了數據分析師和開發者的日常挑戰。傳統的…

前端流行框架Vue3教程:24.動態組件

24.動態組件 有些場景會需要在兩個組件間來回切換&#xff0c;比如 Tab 界面 我們準備好A B兩個組件ComponentA ComponentA App.vue代碼如下&#xff1a; <script> import ComponentA from "./components/ComponentA.vue" import ComponentB from "./…

海拔案例分享-實踐活動報名測評小程序

大家好&#xff0c;今天湖南海拔科技想和大家分享一款實踐活動報名測評小程序&#xff0c;客戶是長沙一家專注青少年科創教育的機構&#xff0c;這家機構平時要組織各種科創比賽、培訓課程&#xff0c;隨著學員增多&#xff0c;管理上的問題日益凸顯&#xff1a;每次組織活動&a…

【MySQL】CRUD

CRUD 簡介 CRUD是對數據庫中的記錄進行基本的增刪改查操作 Create&#xff08;創建&#xff09;Retrieve&#xff08;讀取&#xff09;Update&#xff08;更新&#xff09;Delete&#xff08;刪除&#xff09; 一、新增&#xff08;Create&#xff09; 語法&#xff1a; I…

【數據架構04】數據湖架構篇

? 10張高質量數據治理架構圖 無論你是數據架構師、治理專家&#xff0c;還是數字化轉型負責人&#xff0c;這份資料庫都能為你提供體系化參考&#xff0c;高效解決“架構設計難、流程不清、平臺搭建慢”的痛點&#xff01; &#x1f31f;限時推薦&#xff0c;速速收藏&#…

【Java Web】3.SpringBootWeb請求響應

&#x1f4d8;博客主頁&#xff1a;程序員葵安 &#x1faf6;感謝大家點贊&#x1f44d;&#x1f3fb;收藏?評論?&#x1f3fb; 文章目錄 一、請求 1.1 postman 1.2 簡單參數 1.3 實體參數 1.4 數組集合參數 1.5 日期參數 1.6 JSON參數 1.7 路徑參數 二、響應 2…

競爭性學習:無監督世界的智能聚類引擎

一、競爭性學習&#xff1a;無監督聚類的生物啟發范式 1.1 核心原理&#xff1a;神經元的 “適者生存” 競爭性學習模擬生物神經網絡的競爭機制&#xff1a;多個神經元對輸入數據 “競爭響應”&#xff0c;獲勝神經元&#xff08;與輸入最匹配&#xff09;更新權重&#xff0…

docker面試題(5)

Docker安全么 Docker 利用了 Linux 內核中很多安全特性來保證不同容器之間的隔離&#xff0c;并且通過簽名機制來對鏡像進行 驗證。大量生產環境的部署證明&#xff0c;Docker 雖然隔離性無法與虛擬機相比&#xff0c;但仍然具有極高的安全性。 如何清理后臺停止的容器 可以使用…

同為科技 智能PDU產品選型介紹 EN10/I801CI

智能PDU是一種利用信息技術手段&#xff0c;優化電力的分配和使用。隨著數據中心進行虛擬化部署和為提高計算效率而整合設備&#xff0c;平均機架功率密度在持續增長&#xff0c;幾年前&#xff0c;一個普通機柜需要3-4千瓦電力&#xff0c;而現今9-15千瓦甚至更高電力的機柜則…

Aciviti工作流

1. springBoot和activiti整合 pom.xml文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"…

golang 對象池sync.Pool的實現

Go語言中sync.Pool通過多級緩存機制實現高效對象復用&#xff0c;其核心設計結合了GMP調度模型特性。以下是實現要點分析&#xff1a; P o o l ∑ p 0 G O M A X P R O C S ( l o c a l P o o l p ) v i c t i m C a c h e Pool \sum_{p0}^{GOMAXPROCS}(localPool_p) vict…

Docker run命令-p參數詳解

端口映射基礎語法 docker run -p <宿主機端口>:<容器端口> 操作示例 docker run -d --restartalways --namespug -p 5000:80 registry.aliyuncs.com/openspug/spug參數解析 -d&#xff1a;后臺運行容器--restartalways&#xff1a;設置容器自動重啟--namespug&…

《2.1.4 C語言中的整數類型及類型轉換|精講篇》

后面作者會在2025.5.25 00:00前整理出筆記和思維導圖大家放心&#xff0c;主頁還有其他文章 請先移步歡迎參考 收藏文章 關注博主 高效學習 好了&#xff0c;這小節我們要探討一個相對來說簡單的問題&#xff0c;就是C語言里邊的那些定點整數是如何進行強制類型轉換的。好來看這…

采用多維計算策略(分子動力學模擬+機器學習),顯著提升 α-半乳糖苷酶熱穩定性

字數 978&#xff0c;閱讀大約需 5 分鐘 在工業應用領域&#xff0c;α-半乳糖苷酶在食品加工、動物營養及醫療等方面發揮著重要作用。然而&#xff0c;微生物來源的該酶往往存在熱穩定性不足的問題&#xff0c;限制了其在工業場景中的高效應用。近日&#xff0c;來自江南大學的…

Jetpack Compose預覽調試技巧

Jetpack Compose 預覽(Preview)不顯示是一個常見問題,可能由多種原因導致。以下是系統的調試技巧和解決方案: 1. 檢查基礎配置 Compose 版本兼容性 確保 compose-compiler、compose-ui 等依賴版本一致且與 Kotlin 版本兼容。檢查 build.gradle: android {compileOptions {…

使用 Go 語言實現完整且輕量級高性能的 MQTT Broker

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一種輕量級的發布/訂閱消息傳輸協議。但是目前雖然mqtt的客戶端很多&#xff0c;但是服務端著實不多&#xff0c;常見的服務端如mosquitto或emqx。但是golang語言的實現幾乎找不到。golang的輕量級部署和高并…

uv sync --frozen卡住不動

今天受邀幫同事調試uv卡住不動的問題&#xff0c;同樣的代碼已經在別的服務器跑起來了&#xff0c;換了一臺服務器之后&#xff0c;執行uv sync --frozen沒有按預期創建虛擬環境和安裝依賴。 1. 鏡像源是已經配置好的&#xff0c;pip install也能很快安裝包。 2. 查看了uv.lo…

Spring Boot中如何對密碼等敏感信息進行脫敏處理

以下是常見的脫敏方法及實現步驟&#xff0c;涵蓋配置、日志和API響應等多個層面&#xff1a; ?1. 配置文件敏感信息脫敏? (1) 使用加密庫&#xff08;如Jasypt&#xff09; ?步驟?&#xff1a; 添加依賴&#xff1a; <dependency><groupId>com.github.ulise…

springboot中redis的事務的研究

redis的事務類似于隊列操作&#xff0c;執行過程分為三步&#xff1a; 開啟事務入隊操作執行事務 使用到的幾個命令如下&#xff1a; 命令說明multi開啟一個事務exec事務提交discard事務回滾watch監聽key(s)&#xff1a;當監聽一個key(s)時&#xff0c;如果在本次事務提交之…

python打卡day35@浙大疏錦行

知識點回顧&#xff1a; 三種不同的模型可視化方法&#xff1a;推薦torchinfo打印summary權重分布可視化進度條功能&#xff1a;手動和自動寫法&#xff0c;讓打印結果更加美觀推理的寫法&#xff1a;評估模式 作業&#xff1a;調整模型定義時的超參數&#xff0c;對比下效果。…