详解Objective-C的meta-class
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
比較簡單的一篇英文,重點(diǎn)是講解meta-class。翻譯下,加深理解。
原文標(biāo)題:What is a meta-class in Objective-C?
原文地址:http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
?
本篇將會探討一個在Objective-C中相對陌生的概念 -- meta-class。OC中的每一個類都會有一個與之相關(guān)聯(lián)的meta class,但是你卻幾乎永遠(yuǎn)也不會直接使用到,它們始終籠罩著一層神秘的面紗。筆者將以運(yùn)行時動態(tài)創(chuàng)建一個class為引,通過剖析創(chuàng)建的class pair來弄明白到底meta-class是什么以及更深入的了解它對于OC中對象、類的意義。
?
在運(yùn)行時創(chuàng)建類
以下代碼演示運(yùn)行時創(chuàng)建一個NSError的子類,同時添加一個實例方法給它:
Class newClass = objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0); class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:"); objc_registerClassPair(newClass);函數(shù)ReportFunction就是添加的實例方法的具體實現(xiàn),如下:
void?ReportFunction(id?self,?SEL?_cmd)?? {??NSLog(@"This?object?is?%p.",self);??NSLog(@"Class?is?%@,?and?super?is?%@.",[self?class],[self?superclass]);??Class?currentClass?=?[self?class];??for(?int?i?=?1;?i?<?5;?++i?)??{??NSLog(@"Following?the?isa?pointer?%d?times?gives?%p",i,currentClass);??currentClass?=?object_getClass(currentClass);??}??NSLog(@"NSObject's?class?is?%p",?[NSObject?class]);??NSLog(@"NSObject's?meta?class?is?%p",object_getClass([NSObject?class]));?? }??
看起來一切都很簡單,運(yùn)行時創(chuàng)建類只需要三步:
1、為"class pair"分配空間(使用objc_allocateClassPair).
2、為創(chuàng)建的類添加方法和成員(上例使用class_addMethod添加了一個方法)。
3、注冊你創(chuàng)建的這個類,使其可用(使用objc_registerClassPair)。
?
估計讀者馬上就要問:什么是“class pair"? objc_allocateClassPair只返回一個值:Class。那么pair的另一半在哪里呢?
是的,估計你已經(jīng)猜到了這個另一半就是meta-class,也就是這篇短文的標(biāo)題,但是要解釋清楚它是什么,為什么需要它,還需要交代下OC的對象與類的相關(guān)背景。
?
一個數(shù)據(jù)結(jié)構(gòu)何以成為一個對象?
每個對象都會有一個它所屬的類。這是面向?qū)ο蟮幕靖拍?#xff0c;但是在OC中,這對所有數(shù)據(jù)結(jié)構(gòu)有效。任何數(shù)據(jù)結(jié)構(gòu),只要在恰當(dāng)?shù)奈恢镁哂幸粋€指針指向一個class,那么,它都可以被認(rèn)為是一個對象。
在OC中,一個對象所屬于哪個類,是由它的isa指針指向的。這個isa指針指向這個對象所屬的class。
實際上,OC中對象的定義是如下的樣子:
typedef?struct?objc_object?{??Class?isa;?? }*id;??
這個定義表明:任何以一個指向Class的指針作為首個成員的數(shù)據(jù)結(jié)構(gòu)都可以被認(rèn)為是一個objc_object.
最重要的特性就是,你可以向OC中的任何對象發(fā)送消息,如下這樣:
【@”stringValue"?writeToFile:@"/file.txt?atomically:YES? encoding:?NSUTF8StringEncoding?error:NULL];???
運(yùn)行原理就是,當(dāng)你向一個OC對象發(fā)送消息時(上文的@“stringValue”),運(yùn)行時庫會根據(jù)對象的isa指針找到這個對象所屬的類(上文為例,會找到NSCFString類).這個類會包含一個所有實例方法的列表及一個指向superclass的指針以便可以找到父類的實例方法。運(yùn)行時庫會在類的方法列表以及父類(們)的方法列表中尋找符合這個selector(上文為例,這個selector是"writeToFile:atomically:encoding:error")的方法。找到后即運(yùn)行這個方法。關(guān)鍵點(diǎn)就是類要定義這個你發(fā)送給對象的消息。
什么是meta-class?
至此,你可能已經(jīng)知道,一個OC的類其實也是一個對象,意思就是你可以向一個類發(fā)送消息。
在這個例子中,defaultStringEncoding 被發(fā)送給了NSString類。因為每一個OC的類本身也是一個對象。也就是說Class的數(shù)據(jù)結(jié)構(gòu)必然也是以isa指針開始的在二進(jìn)制級別上與objc_object是完全兼容的。然后一個類結(jié)構(gòu)的下一個字段一定是一個指向super class的指針(或者指向nil,對于基類而言)。
一個類如何定義有很多方法,依賴于你的運(yùn)行時庫版本,但是不管哪種方法,他們都是以一個isa作為第一個字段,接著是superclass字段。
?
為了可以調(diào)用類方法,這個類的isa指針必須指向一個包含這些類方法的類結(jié)構(gòu)體。
這樣就引出了meta-class的概念:meta-class是一個類對象的類。
簡單解釋下:
? ? ? ?當(dāng)你向一個對象發(fā)送消息時,runtime會在這個對象所屬的那個類的方法列表中查找。
? ? ? ?當(dāng)你向一個類發(fā)送消息時,runtime會在這個類的meta-class的方法列表中查找。
meta-class之所以重要,是因為它存儲著一個類的所有類方法。每個類都會有一個單獨(dú)的meta-class,因為每個類的類方法基本不可能完全相同。
meta-class的類又是什么呢?
meta-class,就像Class一樣,也是一個對象。你依舊可以向它發(fā)送消息調(diào)用函數(shù),自然的,meta-class也會有一個isa指針指向其所屬類。所有的meta-class使用基類的meta-class作為他們的所屬類。具體而言,任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己所屬的類。
根據(jù)這個規(guī)則,所有的meta-class使用基類的meta-class作為它們的類,而基類的meta-class也是屬于它自己,也就是說基類的meta-class的isa指針指向它自己。(譯:完美的閉環(huán))
類和meta-class的繼承
就像一個類使用super_class指針指向自己的父類一樣,meta-class的super_class會指向類的super_class的meta-class。一直追溯到基類的meta-class,它的super_class會指向基類自身。(譯:萬物歸根)
這樣一來,整個繼承體系中的實例、類和meta-class都派生自繼承體系中的基類。對于NSObject繼承體系來說,NSObject的實例方法對體系中所有的實例、類和meta-class都是有效的;NSObject的類方法對于體系中所有的類和meta-class都是有效的。
用文字描述總會讓人迷糊,Greg Parker給出了一份精彩的圖譜來展示這些關(guān)系:
點(diǎn)擊打開鏈接
實驗證明:
為了證實以上的論述,讓我們查看下開篇代碼中ReportFunction的輸出。這個函數(shù)的目的就是沿著isa指針進(jìn)行打印。
為了運(yùn)行ErportFunction,我們需要創(chuàng)建一個實例,并調(diào)用report方法。
因為我們并沒有對report方法進(jìn)行聲明,所以我們使用performSelector進(jìn)行調(diào)用,這樣避免編譯器警告。
然后ReportFunction函數(shù)會沿著isa進(jìn)行檢索,來告訴我們class,meta-class以及meta-class的class是什么樣的情況:
?
【注:ReportFunction使用object_getClass來獲取isa指針指向的類,因為isa指針是一個受保護(hù)成員,你不能直接訪問其他對象的isa指針。ReportFunction沒有使用class方法是因為在一個類對象上調(diào)用這個方法是無法獲得meta-class的,它只是返回這個類而已。(所以[NSString class]只是返回NSString類,而不是NSString的meta-class]
以下是程序的輸出:
?
觀察通過isa獲得的地址:
對象的地址是 ? ? ?0x10010c810.
類的地址是 ? ? ? ? 0x10010c600.
類的meta-class地址是 ?0x10010c630.
類的meta-class的類地址是 ? ? ? ? ? ? ? ? 0x7fff71038480.(即NSOjbect的meta-class)
NSObject的meta-class的類地址是它自身。
這些地址的值并不重要,重要的是它們說明了文中討論的從類到meta-class到NSObject的meta-class的整個流程。
結(jié)論:
meta-class是類對象的類,每個類都有自己單獨(dú)的meta-class。所有的類對象并不會屬于同一個meta-class。
meta-class要保證類對象具有繼承體系中基類的所有實例和類方法,以及繼承體系中的所有中間類方法。對于所有NSObject繼承體系下的類,NSObject的實例方法和協(xié)議方法對他們和他們meta-class的對象都要有效。
所有的meta-class使用基類的meta-class作為自己的基類,對于頂層基類的meta-class也是一樣,只是它指向自己而已
轉(zhuǎn)載于:https://my.oschina.net/mexiaobai1315/blog/878712
總結(jié)
以上是生活随笔為你收集整理的详解Objective-C的meta-class的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对进程个数计数
- 下一篇: UE4开发工具 - COOKBOOK