iOS面試題-Runtime

語言: CN / TW / HK

objc實例對象的isa指針指向什麼?有什麼作用?

實例對象的isa指向他的類對象,實例對象可以從他的類對象上找到實例對象所包含的實例方法、屬性、代理等信息。

類對象的isa指向他的元類對象,類對象可以從元類對象中找到類對象所包含的類方法等信息。

一個 NSObject 對象佔用多少內存空間

在XCode中創建一個NSObject對象,按住Command查看NSObject的定義的時候,就會發現,一個NSObject對象的大小就是一個isa指針的大小。一個isa的指針應該是8字節,但是實際使用malloc_size()去驗證的時候卻都是16字節。這是因為,對象在分配內存空間的時候,會進行內存對齊,在iOS中,分配的內存空間都是16字節的整數倍,所以這裏是分配的16字節。

説一下對 class_rw_t 的理解?

rw 代表可讀可寫。

ObjC 類中的屬性、方法還有遵循的協議等信息都保存在 class_rw_t 中

説一下對 class_ro_t 的理解?

存儲了當前類在編譯期就已經確定的屬性、方法以及遵循的協議。

説一下對 isa 指針的理解

isa 可以簡單的用一句話來代替,<是一種>

1 實例對象 isa 指向類對象

2 類對象指 isa 向元類對象

3 元類對象的 isa 指向元類的基類

isa 有兩種類型

1 純指針,指向內存地址

2 NON_POINTER_ISA,除了內存地址,還存有一些其他信息

從上面的代碼可以看出,isa_t對象除了包含內存地址還包含了一些擴展信息

説一下 Runtime 的方法緩存?存儲的形式、數據結構以及查找的過程?

cache_t 增量擴展的哈希表結構。哈希表內部存儲的 bucket_t。

bucket_t 中存儲的是 SEL 和 IMP 的鍵值對。

使用runtime Associate方法關聯的對象,需要在主對象dealloc的時候釋放麼?

無論在MRC下還是ARC下均不需要,被關聯的對象在生命週期內要比對象本身釋放的晚很多,它們會在被NSObject的dealloc調用的object_dispose()方法中釋放。

實例對象的數據結構?

NSObject在Runtime中只有isa一個私有屬性,指向類對象的內存地址,剩下的全是public方法

什麼是method swizzling

OC中的函數調用機制叫消息發送機制,是向一個對象的方法發送消息,去調用這個方法,而查找這個方法的唯一依據就是selector的名字,根據selector找到對應的方法實現(IMP),對其調用。而Runtime提供了一種可能,就是修改selector和IMP的對應關係,從而實現方法調用的交換。

這種改變對應關係的API有三個:

1 method_exchangeImplementations 直接交換兩個方法的實現

2 class_replaceMethod 替換方法的實現

3 method_setImplementation 直接設置某個方法的IMP

能否向編譯後得到的類中增加實例變量?能否向運行時創建的類中添加實例變量? 為什麼?

不能向編譯後得到的類中增加實例變量;

能向運行時創建的類中添加實例變量;

1.因為編譯後的類已經註冊在runtime中,類結構體中的objc_ivar_list實例變量的鏈表和instance_size實例變量的內存大小已經確定,同時runtime會調用 class_setVarLayout或class_setWeakIvarLayout來處理strong和weak引用.所以不能向存在的類中添加實例變量。

2.運行時創建的類是可以添加實例變量,調用 class_addIvar 函數. 但是的在調用 objc_allocateClassPair 之後,objc_registerClassPair 之前,原因同上.

類對象的數據結構?

類對象就是 objc_class。

它的結構相對豐富一些。繼承自 objc_object 結構體,所以包含 isa 指針 isa :指向元類

superClass: 指向父類

Cache: 方法的緩存列表

data: 顧名思義,就是數據。是一個被封裝好的 class_rw_t 。

runtime 如何通過 selector 找到對應的 IMP 地址?

每一個類對象中都一個方法列表,方法列表中記錄着方法的名稱,方法實現,以及參數類型,其實 selector 本質 就是方法名稱,通過這個方法名稱就可以在方法列表中找到對應的方法實現.

runtime 如何實現 weak 變量的自動置 nil?知道 SideTable 嗎?

runtime 對註冊的類會進行佈局,對於 weak 修飾的對象會放入一個 hash 表中。 用 weak 指向的對象內 存地址作為 key,當此對象的引用計數為 0 的時候會 dealloc,假如 weak 指向的對象內存地址是 a,那麼就 會以 a 為鍵, 在這個 weak 表中搜索,找到所有以 a 為鍵的 weak 對象,從而設置為 nil。

SideTable 這個結構體,我給他起名引用計數和弱引用依賴表,因為它主要用於管理對象的引用計數和 weak 表。在 NSObject.mm 中聲明其數據結構:

struct SideTable {
// 保證原子操作的自旋鎖
    spinlock_t slock;
    // 引用計數的 hash 表
    RefcountMap refcnts;
    // weak 引用全局 hash 表
    weak_table_t weak_table;
}

對於 slock 和 refcnts 兩個成員不用多説,第一個是為了防止競爭選擇的自旋鎖,第二個是協助對象的 isa 指針的 extra_rc 共同引用計數的變量(對於對象結果,在今後的文中提到)。這裏主要看 weak 全局 hash 表的結構與作用。

當weak引用指向的對象被釋放時,又是如何去處理weak指針的呢?

當釋放對象時,其基本流程如下:

1.調用 objc_release

2.因為對象的引用計數為0,所以執行 dealloc

3.在dealloc中,調用了_objc_rootDealloc函數

4.在_objc_rootDealloc中,調用了object_disponse函數

5.調用objc_destructinstance函數

6.最後調用objc_clear_deallocating

對象被釋放時調用的 objc_clear_deallocating 函數:

1.從 weak 表中獲取廢棄對象的地址為鍵值的記錄

2.將包含在記錄中的所有附有 weak 修飾符變量的地址,賦值為 nil

3.將 weak 表中該記錄刪除

4.從引用計數表中刪除廢棄對象的地址為鍵值的記錄

十六、objc 中向一個 nil 對象發送消息將會發生什麼?

如果向一個 nil 對象發送消息,首先在尋找對象的 isa 指針時就是 0 地址返回了,所以不會出現任何錯誤。 也不會崩潰。

isKindOfClass 與 isMemberOfClass

1、isKindOfClass可用於判斷對象是否是一個類的成員,或者是該派生類的成員

2、isMemberOfClass可用於判斷對象是否是當前類

一句話就是, isKindOfClass 判斷是否是自己或者父類, isMemberOfClass 判斷是否是自己

Category 在編譯過後,是在什麼時機與原有的類合併到一起的?

  1. 程序啟動後,通過編譯之後,Runtime 會進行初始化,調用 _objc_init。
  2. 然後會map_images.
  3. 接下來調用map_images_nolock.
  4. 再然後就是read_images,這個方法會讀取所有的類的相關信息。
  5. 最後是調用reMethodizeClass:,這個方法是重新方法化的意思。
  6. 在reMethodizeClass: 方法內部會調用 attachCategories: ,這個方法會傳入 Class ,會將方法列表,協議列表等與原有的類合併。最後加入到 class_rw_t 結構體

Category 的實現原理?

Category是被添加在了 class_rw_t 的對應結構裏。

Category 實際上是Category_t的結構體,在運行時,新添加的方法,都被以倒序插入到原有方法列表的最前面,所以不同的Category,添加了同一個方法,執行的實際上是最後一個。

拿方法列表舉例,實際上是一個二維的數組。

Category 如果翻看源碼的話就會知道實際上是一個 _catrgory_t 的結構體。

例如我們在程序中寫了一個 Nsobject+Tools 的分類,那麼被編譯為 C++ 之後,實際上是:

Category在剛剛編譯完的時候,和原來的類是分開的,只有在程序運行起來後,通過 Runtime ,Category和原來的類才會合併到一起。

mememove,memcpy:這倆方法是位移、複製,簡單理解就是原有的方法移動到最後,同時新開闢的空間,把前面的位置留給分類,然後分類中的方法,按照倒序依次插入,可以得出的結論就就是,越晚參與編譯 的分類,裏面的方法才是生效的那個。

[self class] 與 [super class]

下面的參考文檔最後的23題面試題,簡而言之就是:

如果是在實例對象裏面調用,這兩個結果都是son。

如果是直接類方法調用,就是son和father

參考 Runtime面試題.pdf