目錄
1.回顧
1.1 補充
- iOS面試題分析
2.1 load與c++構造函數調用順序
2.2 runtime是什麼?
2.3 initialize調用順序
2.4 同名分類方法的調用順序
2.5 分類和擴展的區別?
1.回顧
在之前的博客中,對OC底層進行了一系列的探索分析,相信小夥伴們都學到了一定的知識,但是底層源碼分析比較枯燥,那麼本次就對一些面試題進行分析。
1.1 補充
在上篇博客iOS底層探索之類的加載(四):類的關聯對象AssociatedObject中主要講了類的擴展和類的關聯對象,移除關聯還沒有講,這裏就做一點補充。
- 移除關聯對象objc_removeAssociatedObjects
void objc_removeAssociatedObjects(id object)
{
if (object && object->hasAssociatedObjects()) {
_object_remove_assocations(object, /*deallocating*/false);
}
}
- _object_remove_assocations
void
_object_remove_assocations(id object, bool deallocating)
{
ObjectAssociationMap refs{};
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.get());
AssociationsHashMap::iterator i = associations.find((objc_object *)object);
if (i != associations.end()) {
refs.swap(i->second);
// If we are not deallocating, then SYSTEM_OBJECT associations are preserved.
bool didReInsert = false;
if (!deallocating) {
for (auto &ref: refs) {
if (ref.second.policy() & OBJC_ASSOCIATION_SYSTEM_OBJECT) {
i->second.insert(ref);
didReInsert = true;
}
}
}
if (!didReInsert)
associations.erase(i);
}
}
// Associations to be released after the normal ones.
SmallVector<ObjcAssociation *, 4> laterRefs;
// release everything (outside of the lock).
for (auto &i: refs) {
if (i.second.policy() & OBJC_ASSOCIATION_SYSTEM_OBJECT) {
// If we are not deallocating, then RELEASE_LATER associations don't get released.
if (deallocating)
laterRefs.append(&i.second);
} else {
i.second.releaseHeldValue();
}
}
for (auto *later: laterRefs) {
later->releaseHeldValue();
}
}
上面👆這是移除關聯對象的代碼,這裏就不過多分析源碼了,我們看看在哪裏調用了
在對象的生命週期,dealloc的時候
* dealloc
// Replaced by NSZombies
- (void)dealloc {
_objc_rootDealloc(self);
}
- _objc_rootDealloc
void
_objc_rootDealloc(id obj)
{
ASSERT(obj);
obj->rootDealloc();
}
對象釋放就會去找rootDealloc
- rootDealloc
inline void
objc_object::rootDealloc()
{
if (isTaggedPointer()) return; // fixme necessary?
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
#if ISA_HAS_CXX_DTOR_BIT
!isa.has_cxx_dtor &&
#else
!isa.getClass(false)->hasCxxDtor() &&
#endif
!isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
object_dispose((id)this);
}
}
這裏會判斷isa.nonpointer、弱引用isa.weakly_referenced、關聯對象isa.has_assoc等等,有的話就進入object_dispose。
- object_dispose
id
object_dispose(id obj)
{
if (!obj) return nil;
objc_destructInstance(obj);
free(obj);
return nil;
}
進入objc_destructInstance銷燬實例
- objc_destructInstance
void *objc_destructInstance(id obj)
{
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj, /*deallocating*/true);
obj->clearDeallocating();
}
return obj;
}
C++方法,關聯對象方法判斷,就去走_object_remove_assocations也就是最開頭的那個移除關聯對象方法。
所以,關聯對象不需要我們手動移除,會在dealloc時自動進行釋放
2. iOS面試題分析
2.1 load與c++構造函數調用順序
- load是在dyld回調load_images中進行調用的,這個回調是在_objc_init的過程中進行註冊的。
- C++構造函數對於同一個image而言是在load回調後dyld調用的。(並不是絕對的)
- image內部是先加載所有類的+ load,再加載分類的+ load,最後加載C++全局構造函數。(類load -> 分類load -> C++構造函數)。
- +load是objc中調用的,C++全局構造函數是在dyld中調用的。(image內部的順序默認是按Compile Sources中順序進行加載的,當然對於有依賴庫的image,依賴庫+load先被調用)。
- Dyld初始化image是按Link Binary With Libraries順序逐個初始化的,從下標1開始,最後再初始化主程序(下標0)。
- 當然對於同一個image而言C++構造函數在load之後調用並不是絕對的。比如objc系統庫,在進行dyld註冊回調之前調用了自身庫的C++構造函數(自啓)。
2.2 runtime是什麼?
- runtime是由C 和C++/ 彙編 實現的⼀套API,爲OC語⾔加⼊了⾯向對象,運⾏時的功能。
- 是一種運行機制,不是底層。dyld、彙編、objc、macho纔是底層。
- 平時編寫的OC代碼,在程序運行過程中,其實最終會轉換成Runtime的C語言代 碼,Runtime 是 Objective-C的幕後工作者。
2.3 initialize調用順序
initialize是在第一次發送消息的時候進行的調用。
load是在load_images的時候調用的,load比initialize調用時機早(initialize在lookupimporforward慢速消息查找的時候調用)。
整個調用順序load > C++構造函數 > initialize。
2.4 同名分類方法的調用順序
同名分類方法調用順序分爲兩種情況:
- 分類合併到主類的情況,也就是隻有一個/或者沒有load方法,這個時候整個方法列表一維數組(不考慮其它動態添加方法的情況)。最後編譯的同名分類方法會放在主類與其它分類前面,在進行方法二分查找的時候先從中間開始查找,找到對應方法SEL的時候會繼續往前查找,直到找到最前面的同名方法。
- 分類沒有合併到主類的情況,多個load方法這個時候整個方法列表是一個一個二維數組,後編譯加載的分類在數組前面,查找方法的時候從前面開始查找。
- 也就是同名方法最終會找到後編譯加載的分類的同名方法,查找過程不一樣而已。
在iOS底層探索之類的加載(三): attachCategories分析博客裏面也介紹了分類和load方法的一些加載。
2.5 分類和擴展的區別?
首先我們來看看什麼是分類和擴展
category: 類別/分類
- 專門用來給類添加新的方法
- 不能給類添加成員屬性,添加了成員變量,也無法取到
- 注意:其實可以通過runtime給分類添加屬性
- 分類中用@property定義變量,只會生成變量的 getter,setter方法的聲明,不能生成方法實現和帶下劃線的成員變量。
extension:類擴展
- 可以說成是特殊的分類,也稱作匿名分類
- 可以給類添加成員屬性,但是是私有變量
- 可以給類添加方法,也是私有方法
- 分類我們已經很熟悉了,這裏就不必過多贅述了,下面介紹下擴展
extension
類擴展,我們平時用的是非常多的,如下
what ? 什麼,這就是擴展嗎?天天用居然不知道!
是的,這就是擴展,平時用的是非常之多,但是很多人都不知道。
注意:類擴展要放在聲明之後,實現之前,否則會報錯。
更多內容持續更新
🌹 喜歡就點個贊吧👍🌹
🌹 覺得有收穫的,可以來一波,收藏+關注,評論 + 轉發,以免你下次找不到我😁🌹
🌹歡迎大家留言交流,批評指正,互相學習😁,提升自我🌹
如果你正在跳槽或者正準備跳槽不妨動動小手,添加一下咱們的交流羣1012951431來獲取一份詳細的大廠面試資料爲你的跳槽多添一份保障。