筆者翻譯自[objc explain]: Classes and metaclasses
Object-C 是基于類的對象系統(tǒng)元暴。每一個對象都是一些類的實例律秃;這個對象的 isa 指針指向它所屬的類梗醇。該類描述這個對象的數(shù)據(jù)信息:內(nèi)存分配大小和實例變量的類型與布局查乒。這個類也描述了對象的行為:它能夠響應(yīng)的選擇器和它實現(xiàn)的實例方法。
類的方法列表是一個實例方法的集合熔萧,是對象響應(yīng)的選擇器。當(dāng)你向一個實例發(fā)送一條消息,objc_msgSend()查詢對象所屬類(和它的父類荷科,如果有)的方法列表,去決定調(diào)用哪個方法纱注。
每個 Object-C 類也是一個對象畏浆。它有一個 isa 指針和其他數(shù)據(jù),并且可以響應(yīng)選擇器狞贱。當(dāng)你調(diào)用一個“類方法”刻获,例如:[NSObject alloc],你實際上是向類對象發(fā)送了一條消息瞎嬉。
因為一個類是一個對象蝎毡,它肯定也是其他類的實例厚柳,這個類是元類(metaclass)。元類是關(guān)于類對象的描述沐兵,就像類是普通實例對象的描述一樣别垮。實際上,元類的方法列表正是類方法:該類對象響應(yīng)的選擇器扎谎。當(dāng)你向一個類(元類的實例)發(fā)送消息碳想,objc_msgSend()查詢元類(和它的父類,如果有)的方法列表簿透,去決定調(diào)用哪個方法移袍。元類為類對象描述類方法,就像類為實例對象描述實例方法一樣老充。
元類葡盗?元類鏈?zhǔn)且恢毕蛳碌膯幔坎皇欠茸牵粋€元類是根元類的實例觅够;根元類是它自身的實例。isa 指針鏈以一個環(huán)結(jié)束:實例指向類指向根元類指向根元類自身巷嚣。元類的 isa 指針并不重要喘先,因為在現(xiàn)實世界中,沒人會向元類對象發(fā)送消息廷粒。
元類的父類就要更重要了窘拯。元類的父類鏈平行于類的父類鏈,因此類方法跟實例方法一樣被繼承坝茎。并且根元類的父類是根類涤姊,因此每個類對象都響應(yīng)根類的實例方法。最后嗤放,一個類對象就像其他對象一樣是根類的實例(或子類)思喊。
暈了吧?這個圖肯定會幫助你次酌。記住恨课,當(dāng)一個消息被發(fā)送到任何對象,都會從對象的 isa 指針開始尋找應(yīng)該調(diào)用的方法岳服,然后繼續(xù)沿著父類鏈向上尋找剂公。“實例方法”被類定義吊宋,“類方法”被元類和根類(非元類)定義诬留。
在合理的電腦科學(xué)語言理論中,一個類和元類的層次結(jié)構(gòu)可以是更自由的形式,像更深的元類鏈以及任何單一的元類實例化多個類文兑。Object-C 使用元類實現(xiàn)了類方法這樣的實際目的盒刚,但在其他情況下趨向于隱藏元類。例如绿贞,[NSObject class]等價于[NSObject self]因块,盡管按正常的理解它應(yīng)該返回 NSObject->isa 指向的元類。Object-C 語言有一些實際情況的妥協(xié)籍铁,在這里涡上,它不能得到類的實際結(jié)構(gòu),元類拒名。