類的加載

在上一篇文章中,我們了解了objcdyld的關聯(lián),那么關聯(lián)之后怎么對類進行加載的呢耘子, 本篇將對類的加載進行探索和分析。

在上一篇文章中我們通過objc_init里面的_dyld_objc_notify_register 來到了_read_images

_read_images

我們點到_read_images里面去球切,把項目跑起來谷誓,然后打斷點調試,看看走哪些代碼

readClass讀取自己研究的類

來到3597行的時候吨凑,我們在里面判斷一下讀取自己的類捍歪。

readClass

因為這里還會讀取很多系統(tǒng)的類,而系統(tǒng)的類我們又不好操控怀骤,所以在readClass里面费封,我們寫上這么一段代碼,讀取到我們自己的類蒋伦,,讓自己創(chuàng)建的類進來焚鹊。

斷點調試

來到我們自己類之后接著往下走痕届。通過在判斷條件里面打斷點的方式,判斷每個if下面有沒有走末患。

for (EACH_HEADER)

接著來到realizeClassWithoutSwift實現(xiàn)當前的類研叫,我們在自己研究的類這里打個斷點,發(fā)現(xiàn)沒有進來璧针,這是啥情況嚷炉,一般人又玩不進來了。 其實蘋果也給了注釋 Realize non-lazy classes (for +load methods and static instances) 大概意思是需要實現(xiàn)非懶加載的類才可以進去探橱,用+load方法來實現(xiàn)申屹。那么我們在LGPerson里面加一個load方法試試

image.png

加完之后我們再來運行一下看看進沒進來

非懶加載類進到分類

果然進來了,從而得出加了load方法后讓類提前實現(xiàn)成為非懶加載類隧膏,那么懶加載類在什么時候呢哗讥,我們把load方法注釋來到realizeClassWithoutSwiftbt打個斷點,然后打印一下堆棧

bt堆棧

在我們[LGPerson alloc];其實是進行了一次消息的發(fā)送_objc_msgSend_uncached胞枕,也就是當你要用到這個類的時候才會去實現(xiàn)這個類杆煞,這樣大大減少了程序啟動前的內存加載。

我們用一張PPT來總結下懶加載和非懶加載的區(qū)別:

懶加載和非懶加載區(qū)別

類的加載

明白了懶加載和非懶加載的區(qū)別之后,回到_read_images進來的斷點里面决乎,斷點進來后我們接著進到realizeClassWithoutSwift里面去队询,這個方法也是本篇文章研究的重點,因為在類相關的判斷里面都有realizeClass實現(xiàn)類的方法构诚。

從而能看出來類就是在realizeClassWithoutSwift這個里面實現(xiàn)的蚌斩,其實之前在lookupimp慢速查找的時候也提到過,那我們點進去看一下到底是怎么實現(xiàn)的

realizeClassWithoutSwift只研究本類

首先在開始前還是加一句只研究本類的代碼唤反, 排除其它類和元類凳寺,同時在自己類里面加了一些方法和屬性,方便研究彤侍。

LGPerson.h

加好之后肠缨,我們回到realizeClassWithoutSwift,接下來再斷點定到自己的類盏阶,接著往下看

讀取data

在這個地方從我們的MachO里面讀取到了我們的data晒奕,按照一定的格式轉換成class_ro_t賦值給了臨時變量ro

設置data

拿到ro之后判斷是否為元類名斟,顯然不是脑慧,所以來到else里面,來到里面之后第一句代碼rw = objc::zalloc<class_rw_t>(); 申請和開辟class_rw_t砰盐,此時rw還只是剛創(chuàng)建闷袒,是空的,然后set_roro放到了rw里面岩梳,再setDatarw給了LGPerson囊骤,設置完了之后LGPerson還是空的,接著往下走

確定繼承鏈的關系

走到這兩句就意味著把我們類信息確定好之后冀值,再確定父類和元類也物,從LGPerson 類信息 -> 父類 -> 元類 就是為了確定繼承鏈關系,實現(xiàn)完了之后就會來到isa的設置列疗,完了之后就把整個繼承鏈設置好了滑蚯。

接著往下走,設置一些其它信息抵栈,比如setHasCxxDtor告材,設置Cxx,這就是為什么類里面有這么個Cxx的方法竭讳,這是系統(tǒng)默認設置的创葡。

image.png

設置完了之后來到methodizeClass這句重點,點進去绢慢,然后在methodizeClass繼續(xù)做一個判斷灿渴,只研究當前自己的類洛波,因為在realizeClassWithoutSwift遞歸了父類和元類,所以methodizeClass會進來父類和元類骚露,寫這個判斷就是為了排除別的類蹬挤。

methodizeClass

來到自己的類之后,把rw棘幸,ro焰扳,rwe拿了出來

auto rw = cls->data();
auto ro = rw->ro();
auto rwe = rw->ext();

然后把baseMethods拿出來

method_list_t *list = ro->baseMethods();
    if (list) {
        prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
        if (rwe) rwe->methods.attachLists(&list, 1);
    }

然后走到prepareMethodLists,看下里面做了什么操作

prepareMethodLists

看到下面有一句fixupMethodList误续,注釋的意思是修正方法list吨悍,應該是對方法排序的意思,我們點進去看一下

fixupMethodList

果然蹋嵌,把這里把方法的名字進行一系列的處理之后開始sort 排序

SortBySELAddress

根據sel的名字來進行排序育瓜,排序前和排序后分別來打印一下

排序打印
注意,這里是根據名字的地址大小進行排序的栽烂,而不是文字的字符串大小排序的躏仇。

把順序排好之后,來到rwe腺办,我斷點走完之后發(fā)現(xiàn)rwe始終為NULL焰手,這是啥情況,這個地方讓很多人百思不得其解怀喉,在后面我會為大家揭曉书妻。我們先來看一下methodizeClass這個方法上面的注釋Attach categories 附加分類,說明跟分類有關系躬拢,既然說到分類那就看看分類里面到底有些什么東西驻子,可以通過Clang來看,我這里就直接搜索category_t來看

分類的本質

看到category_tclassMethods估灿,protocols等等,那么這里面的這些東西怎么加到我們的類里面去的呢缤剧,帶著這個問題繼續(xù)來探索:

我們在methodizeClass往下翻會看到分類相關的東西

分類加載的調用

1480行有一個attachToClass馅袁,非常好,我們點進去看到底是怎么加到類里面去的

attachToClass

老規(guī)矩荒辕,在前面還是加上只研究本類的判斷汗销, 看到category_list &list = it->second; ,然后在下面進行實現(xiàn)分類的判斷調用了attachCategories抵窒, 如果if (flags & ATTACH_CLASS_AND_METACLASS) 滿足弛针,則說明類和分類都實現(xiàn)了,如果不滿足李皇,則說明主類沒有實現(xiàn)load方法,而分類實現(xiàn)了load方法需要進行加載了削茁,就會來到else下面宙枷。

我們點到attachCategories里面去看看

attachCategories

來到這里面之后我們意外的發(fā)現(xiàn) auto rwe = cls->data()->extAllocIfNeeded();rwe原來就在這里進行創(chuàng)建或者獲取茧跋,看來要對本類進行添加分類信息的時候才會處理這個rwe慰丛。那么還有哪些地方有用到嗎,我們全局搜索

全局搜索extAllocIfNeeded

通過全局搜索能夠看出rwe除了在添加分類以外瘾杭,還在除了系統(tǒng)外的addMethod诅病,addProtocoladdProperty這些地方用到過粥烁,說白了正如WWDC里面所說的只有對原始的內存進行處理和修改的時候我們才會用到rwe贤笆。

明白了rwe之后,我們再回attachCategories接著打一個斷點進入LGPerson當前要研究的類讨阻,然后開始遍歷cats_count

遍歷cats_count

可以看到這里來到的是LGPerson的分類LGA芥永,然后拿到分類的method_list

倒序插入

拿到分類的方法列表之后,判斷mcount是否等于ATTACH_BUFSIZ变勇,表示最大修改次數(shù)為64次恤左, 如果不等于則mlists[64 - 1] = mlist進行倒序插入

if (mcount > 0) {
        prepareMethodLists(cls, mlists + ATTACH_BUFSIZ - mcount, mcount, NO, fromBundle);
        rwe->methods.attachLists(mlists + ATTACH_BUFSIZ - mcount, mcount);
        if (flags & ATTACH_EXISTING) flushCaches(cls);
    }

倒序插入完了之后會來到

if (mcount > 0) {
        prepareMethodLists(cls, mlists + ATTACH_BUFSIZ - mcount, mcount, NO, fromBundle);
        rwe->methods.attachLists(mlists + ATTACH_BUFSIZ - mcount, mcount);
        if (flags & ATTACH_EXISTING) flushCaches(cls);
    }

到這一步,我們數(shù)據已經準備好了搀绣,那么到底是怎么加載到我們類里面去的呢飞袋,還有在什么時機加進去的,這將在下篇文章進行展開分析链患。 本來這篇文章只講類的加載的巧鸭,結果摸到分類來了,也算是提前給下一篇文章做個預告

未完待續(xù)麻捻。纲仍。。贸毕。

iOS 底層原理 文章匯總

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末郑叠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子明棍,更是在濱河造成了極大的恐慌乡革,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摊腋,死亡現(xiàn)場離奇詭異沸版,居然都是意外死亡,警方通過查閱死者的電腦和手機兴蒸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門视粮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人橙凳,你說我怎么就攤上這事蕾殴⌒ψ玻” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵区宇,是天一觀的道長娃殖。 經常有香客問我,道長议谷,這世上最難降的妖魔是什么炉爆? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮卧晓,結果婚禮上芬首,老公的妹妹穿的比我還像新娘。我一直安慰自己逼裆,他們只是感情好郁稍,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胜宇,像睡著了一般耀怜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桐愉,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天财破,我揣著相機與錄音,去河邊找鬼从诲。 笑死左痢,一個胖子當著我的面吹牛,可吹牛的內容都是我干的系洛。 我是一名探鬼主播俊性,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼描扯!你這毒婦竟也來了定页?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤绽诚,失蹤者是張志新(化名)和其女友劉穎拯勉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體憔购,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年岔帽,在試婚紗的時候發(fā)現(xiàn)自己被綠了玫鸟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡犀勒,死狀恐怖屎飘,靈堂內的尸體忽然破棺而出妥曲,到底是詐尸還是另有隱情,我是刑警寧澤钦购,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布檐盟,位于F島的核電站,受9級特大地震影響押桃,放射性物質發(fā)生泄漏葵萎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一唱凯、第九天 我趴在偏房一處隱蔽的房頂上張望羡忘。 院中可真熱鬧,春花似錦磕昼、人聲如沸卷雕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漫雕。三九已至,卻和暖如春峰鄙,著一層夾襖步出監(jiān)牢的瞬間浸间,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工先馆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留发框,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓煤墙,卻偏偏與公主長得像梅惯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仿野,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344