好久沒寫簡書了,一是因為懶,二也是因為懶吧...
本文主要翻譯了 Objective-C Runtime Programming Guide 這篇蘋果的文檔扁藕,不是逐字逐句翻譯,其中會有自己的補充,如果翻譯理解有偏差或錯誤槽华,煩請指正。
本來想研究下YYModel的源碼趟妥,發(fā)現(xiàn)里面用到的Runtime的知識挺多猫态,所以就把原來記錄的runtime的知識看了看,又翻譯了一下這篇披摄。
參考閱讀
Objective-C Runtime Programming Guide 蘋果官方文檔
Objective-C Runtime Reference 蘋果官方文檔
The Objective-C Programming Language 蘋果官方文檔
1 Introduction——介紹
Objective-C 會盡可能地將許多決策從編譯時(compile time)亲雪、鏈接時(link time)推遲到運行時(runtime)進(jìn)行。這意味著OC不僅需要一個編譯器疚膊,還需要一個運行時系統(tǒng)去執(zhí)行編譯的代碼义辕。換句話來說,對于OC來說寓盗,runtime系統(tǒng)相當(dāng)于一個操作系統(tǒng)灌砖,runtime系統(tǒng)使OC可以工作運行。
2 Interacting with the Runtime——與Runtime的交互
OC程序可以在3個不同的層面上與runtime系統(tǒng)進(jìn)行交互:
- 通過OC源碼傀蚌;
- 通過Foundation framework中的NSObject類(內(nèi)省方法)基显;
- 直接調(diào)用runtime函數(shù)方法
2.1 Objective-C Source Code——OC源碼
大多數(shù)情況下,runtime系統(tǒng)會默默地在后臺運行善炫。
當(dāng)編譯包含OC的類撩幽、方法的代碼時,編譯器會創(chuàng)建實現(xiàn)了動態(tài)特性的數(shù)據(jù)結(jié)構(gòu)和函數(shù)箩艺。數(shù)據(jù)結(jié)構(gòu)會捕獲類(class)摸航、分類(category)制跟、協(xié)議(protocol)中的各種信息:包括類和協(xié)議對象[參考The Objective-C Programming Language中的Defining a Class 和 Protocols]、方法選擇子(method selectors)酱虎、實例變量等雨膨。
runtime最主要的功能就是發(fā)送消息,這點在下面會說明读串。
理解:編譯時生成運行時的所使用的數(shù)據(jù)結(jié)構(gòu)聊记。
2.2 NSObject Methods——NSObject中的內(nèi)省方法
Cocoa框架中的大部分對象都繼承自NSObject類(但是NSProxy類是個例外),因此這些對象都繼承了NSObject類中定義的方法恢暖。這些繼承下來的方法建立了每個實例和每個類的固有行為排监。
在一些繼承下來的方法中,NSObject只定義了一個模板杰捂,但是沒有給出實現(xiàn)的代碼舆床,例如description這個實例方法,它需要子類自己去覆蓋實現(xiàn)嫁佳。
還有一些NSObject中的方法挨队,叫做內(nèi)省(introspection)方法蒿往,可以實現(xiàn)從runtime系統(tǒng)中查詢信息:
- isKindOfClass: 是否是某一個類或其子類
- isMemberOfClass: 是否是某一個類
- respondsToSelector: 是否能夠響應(yīng)某個方法
- conformsToProtocol: 是否遵守了某個協(xié)議
- methodForSelector: 提供方法實現(xiàn)的地址
2.3 Runtime Functions——Runtime函數(shù)方法
運行時系統(tǒng)是一個動態(tài)共享庫盛垦,具有一個公共接口,該公共接口由位于目錄/ usr / include / objc中的頭文件中的一組函數(shù)和數(shù)據(jù)結(jié)構(gòu)組成瓤漏。這里面的很多函數(shù)可以提供運行時系統(tǒng)的功能腾夯。具體見Objective-C Runtime Reference。
3 Messaging——消息傳遞(注意蔬充,不是消息轉(zhuǎn)發(fā))
這一章描述了消息表達(dá)式是怎樣轉(zhuǎn)換為 objc_msgSend 函數(shù)調(diào)用的(其實OC中的調(diào)用方法本質(zhì)是給對象發(fā)送一條消息)妖爷,以及如何按名稱調(diào)用方法歧沪,以及如何利用objc_msgSend方法窗看,以及如何在你需要的情況下規(guī)避掉動態(tài)綁定膳算。
3.1 The objc_msgSend Function——objc_msgSend函數(shù)
OC中,消息沒有綁定到方法實現(xiàn)趾浅,直到runtime時愕提。
理解:也就是說馒稍,在運行時皿哨,才能夠在內(nèi)存中找到這個方法實現(xiàn)的地址。
編譯器會將下面的消息表達(dá)式轉(zhuǎn)化為objc_msgSend函數(shù):
[receiver message]
轉(zhuǎn)化為:
objc_msgSend(receiver, selector)
若攜帶有參數(shù)的話纽谒,轉(zhuǎn)化為:
objc_msgSend(receiver, selector, arg1, arg2, ...)
消息傳遞完成了動態(tài)綁定所需要的一切:
- 首先证膨,它會找到selector選擇子的方法實現(xiàn)。由于相同的方法可以由不同的類實現(xiàn)鼓黔,因此找到selector的方法實現(xiàn)需要精確到接收這個消息的類央勒。
- 然后不见,它會調(diào)用這個方法實現(xiàn),并將參數(shù)傳遞給這個方法實現(xiàn)崔步。
- 最后稳吮,它會將方法實現(xiàn)的返回值作為自己的返回值返回。
注意:編譯器會生成這個消息函數(shù)objc_msgSend的調(diào)用井濒,不要自己調(diào)用objc_msgSend函數(shù)
消息傳遞的關(guān)鍵在于編譯器為每個類和對象創(chuàng)建的結(jié)構(gòu)灶似。每個類結(jié)構(gòu)包含兩個基本元素:
- superclass父類的指針
- 一個類調(diào)度表(class dispatch table)(應(yīng)該就是方法列表)。這個表上有方法selector與這個方法實現(xiàn)的地址的對應(yīng)瑞你,比如酪惭,setOrigin這個selector和setOrigin這個方法實現(xiàn)的地址的關(guān)聯(lián)。
當(dāng)一個新的對象被創(chuàng)建時者甲,會給它分配內(nèi)存春感,并且會初始化它的實例變量。在這個對象的變量里虏缸,第一個是指向類結(jié)構(gòu)的指針鲫懒,稱為isa指針。這個isa指針可以讓對象去訪問它所屬的類寇钉,并可以通過這個類訪問其繼承的所有類刀疙。
當(dāng)一條消息被發(fā)送給一個對象時,消息傳遞函數(shù)會跟隨對象的isa指針找到其類結(jié)構(gòu)扫倡,并在類結(jié)構(gòu)中的方法調(diào)度表(dispatch table)中尋找方法selector谦秧。若沒有找到,objc_msgSend 則會跟隨類結(jié)構(gòu)的superclass指針去找父類撵溃,并在父類的方法調(diào)度表中尋找疚鲤。若找到了selector,會調(diào)用方法實現(xiàn)缘挑。
這個就被稱作消息的動態(tài)綁定——在運行時去尋找方法實現(xiàn)集歇。
為了加快消息傳遞的過程,會有一個對方法列表的緩存语淘,消息傳遞時首先會去找這個方法列表的緩存(根據(jù)理論诲宇,曾經(jīng)使用過的方法可能會再次使用)。如果方法選擇器在緩存中惶翻,則消息傳遞僅比函數(shù)調(diào)用慢一點姑蓝。
理解:實例的isa指針指向類對象,類對象的isa指針指向元類吕粗;動態(tài)綁定的一個壞處:比直接調(diào)用函數(shù)實現(xiàn)要慢纺荧,即使有了緩存。
3.2 Using Hidden Arguments——隱藏參數(shù)
當(dāng)objc_msgSend找到方法實現(xiàn)時,它就會調(diào)用這個方法實現(xiàn)并將方法參數(shù)傳進(jìn)去宙暇。同時输枯,它還會給方法實現(xiàn)傳遞兩個隱藏參數(shù):
- 接收消息的對象
- 方法的selector選擇子
這兩個參數(shù)為方法實現(xiàn)指明了有關(guān)調(diào)用它的消息表達(dá)式的參數(shù)信息,這兩個參數(shù)之所以是隱藏的占贫,是因為沒有在方法源碼中進(jìn)行聲明桃熄,而是在代碼編譯的時候被插入進(jìn)去的。
雖然沒有聲明這兩個參數(shù)型奥,但是在方法的源碼中仍然可以引用它們蜻拨,
在方法里,使用self指的是對象本身桩引,_cmd指的是selector選擇子本身缎讼。
- strange
{
id target = getTheReceiver();
SEL method = getTheMethod();
if ( target == self || method == _cmd )
return nil;
return [target performSelector:method];
}
3.3 Getting a Method Address——獲取方法地址
規(guī)避動態(tài)綁定的唯一方式:獲取到方法的地址,然后直接調(diào)用它坑匠。在極少數(shù)的情況下血崭,當(dāng)你希望避免掉連續(xù)傳遞消息時的開銷時,這么做可能是合適的厘灼。
NSObject的methodForSelector:方法可以獲取到方法實現(xiàn)的地址夹纫,你可通過這個方法獲取到一個指針,然后使用這個指針直接調(diào)用方法實現(xiàn)设凹。
methodForSelector: 是一個內(nèi)省方法舰讹,不是OC語言的功能,是Cocoa的運行時系統(tǒng)提供的方法闪朱。
4 Dynamic Method Resolution——動態(tài)方法解析
這一章說明了月匣,你可以如何動態(tài)地提供一個方法的實現(xiàn)。
4.1 Dynamic Method Resolution——動態(tài)方法解析
在聲明屬性的時候奋姿,可以使用@dynamic指令去描述這個屬性锄开。
@dynamic propertyName;
@dynamic 就會告訴編譯器不要去生成這個屬性的getter和setter方法,這些方法會動態(tài)的提供称诗。
使用 resolveInstanceMethod: 為實例方法動態(tài)地提供selector的實現(xiàn)萍悴;
使用 resolveClassMethod: 為類方法動態(tài)地提供selector的實現(xiàn)。
一個OC方法只是一個帶有最少兩個參數(shù)(self寓免、_cmd)的C函數(shù)癣诱。可以使用 class_addMethod 函數(shù)添加一個函數(shù)到一個類中作為一個方法袜香。
void dynamicMethodIMP(id self, SEL _cmd) {
// implementation ....
}
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
@end
一個類有機(jī)會在消息轉(zhuǎn)發(fā)機(jī)制啟動之前動態(tài)地解析一個方法(動態(tài)地添加方法)撕予。如果 respondsToSelector: 或者 instancesRespondToSelector: 被調(diào)用了,則動態(tài)方法解析器將會有機(jī)會首先為選擇子提供IMP困鸥。當(dāng)想啟動消息轉(zhuǎn)發(fā)機(jī)制時嗅蔬,可以在 respondsToSelector: 或 instancesRespondToSelector: 為這些selector中返回NO。
理解:當(dāng)對象接收到無法解析的消息時疾就,也就是說消息傳遞沒有找到這個方法時澜术,才會進(jìn)入消息轉(zhuǎn)發(fā)。
動態(tài)方法解析是消息轉(zhuǎn)發(fā)的第一步猬腰,看消息的接受者能否動態(tài)的添加方法鸟废,以處理當(dāng)前的未知選擇子。若動態(tài)方法解析無法動態(tài)的添加方法姑荷,下面就會進(jìn)入完整的消息轉(zhuǎn)發(fā)機(jī)制盒延。
4.2 Dynamic Loading——動態(tài)加載
一個OC工程可以在運行時加載和鏈接新的類和分類,新代碼被合并到程序中鼠冕,并且與剛開始時加載的類和分類沒有區(qū)別添寺。
動態(tài)加載可以被用來做許多事情,例如懈费,系統(tǒng)的偏好設(shè)置中的各個模塊就是動態(tài)加載的计露。
在Cocoa環(huán)境中,通常使用動態(tài)加載來定制應(yīng)用程序憎乙。
有一個runtime函數(shù)(objc_loadModules)可以在Mach-O文件中執(zhí)行OC模塊的動態(tài)加載票罐,但是Cocoa的NSBundle類為動態(tài)加載提供了更方便的接口,即面向?qū)ο蟮门c相關(guān)服務(wù)集成泞边。
推測:這個動態(tài)加載應(yīng)該是與組件化有關(guān)该押。
5 Message Forwarding——消息轉(zhuǎn)發(fā)
當(dāng)給一個對象發(fā)送消息,但這個對象無法處理這條消息時阵谚,會發(fā)生錯誤蚕礼。但是,在報出這個錯誤之前梢什,Runtime運行時系統(tǒng)給了這個對象第二次機(jī)會去處理這條消息闻牡。
5.1 Forwarding——轉(zhuǎn)發(fā)
如果將消息發(fā)送給一個無法處理該條消息的對象時,在報錯之前绳矩,runtime系統(tǒng)會給這個對象發(fā)送 forwardInvocation:(NSInvocation *)invocation 消息罩润,invocation里面封裝了原始的消息和參數(shù)。
你可以實現(xiàn) forwardInvocation: 方法以對消息提供默認(rèn)響應(yīng)或以其它方式避免錯誤翼馆。forwardInvocation: 通常用來將消息轉(zhuǎn)發(fā)給另一個對象割以。
給個例子:現(xiàn)在你想設(shè)計一個對象,它能夠響應(yīng) negotiate 這條消息(方法)应媚,并且你想讓它的響應(yīng)里包含另一種對象的響應(yīng)(簡單理解严沥,就是這個方法里面你想調(diào)用其它對象的方法)。你可以通過繼承來實現(xiàn)這個方法中姜,當(dāng)不想或無法繼承的時候消玄,你也可以這么實現(xiàn)這個例子:
// 這個代碼很奇怪跟伏,[someOtherObject negotiate]和self不是同一個級別的返回吧
- (id)negotiate
{
if ( [someOtherObject respondsTo:@selector(negotiate)] )
return [someOtherObject negotiate];
return self;
}
也可以這么做,使用運行時方法 forwardInvocation: 翩瓜,它 的工作方式如下:
- 當(dāng)對象中沒有與消息里面的選擇子selector相匹配的方法受扳,這時候runtime運行時系統(tǒng)會給這個對象發(fā)送forwardInvocation:消息來通知對象。
- 每個對象都是從NSObject對象里繼承forwardInvocation: 方法的兔跌,NSObject里這個方法默認(rèn)只是調(diào)用了dosNotRecognizeSelector:(也就是平常selector does not recognized那個報錯的來源)勘高。
- 通過覆蓋NSObject的forwardInvocation:方法來實現(xiàn)將消息轉(zhuǎn)發(fā)給其它對象。
要轉(zhuǎn)發(fā)消息坟桅,forwardInvocation: 方法需要做這兩點:
- 確定這個消息要去哪里
- 將原始參數(shù)發(fā)送到那里去
invokeWithTarget: 方法可以實現(xiàn)消息的發(fā)送
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([someOtherObject respondsToSelector:
[anInvocation selector]])
[anInvocation invokeWithTarget:someOtherObject];
else
// 注意:當(dāng)發(fā)現(xiàn)這個消息不能被當(dāng)前對象轉(zhuǎn)發(fā)時华望,應(yīng)該調(diào)用父類的同名方法forwardInvocation:,
// 這樣才能最終走到NSObject的默認(rèn)方法實現(xiàn)仅乓,調(diào)用dosNotRecognizeSelector:報出錯誤
[super forwardInvocation:anInvocation];
}
這個被轉(zhuǎn)發(fā)的消息的返回值會返回給消息的發(fā)送者赖舟,所有類型的返回值都可以被傳遞給發(fā)送方。
forwardInvocation: 可以做很多很多事情夸楣,它提供了在消息轉(zhuǎn)發(fā)鏈中鏈接對象的機(jī)會建蹄,為程序設(shè)計開辟了可能性:
- 它可以當(dāng)做一個未識別消息的分發(fā)中心,將其打包發(fā)送給其它不同的接收者裕偿;
- 或者它可以當(dāng)做一個中轉(zhuǎn)站洞慎,將所有消息發(fā)送到同一個目的地;
- 它還可以將一種類型的消息轉(zhuǎn)換為另一種嘿棘;
- 它可以將一些消息“吞”掉劲腿,這樣這些消息既沒有響應(yīng)也不會有報錯;
- 它可以將多個消息合并為一個(這個不太懂鸟妙,多個方法其實本質(zhì)上調(diào)用的是一個焦人?)
注意,forwardInvocation: 方法是在消息轉(zhuǎn)發(fā)過程中被調(diào)用的重父,也就是說花椭,如果消息接受者默認(rèn)實現(xiàn)了某個(消息)方法,它就不會再走消息轉(zhuǎn)發(fā)了房午,也就不會調(diào)用forwardInvocation:了矿辽。
更多的信息可以看NSInvocation。
補充:在動態(tài)方法解析和forwardInvocation:之間應(yīng)該還有一步郭厌,-(id)forwardingTargetForSelector:(SEL)selector袋倔,這個方法可以將消息轉(zhuǎn)發(fā)給其它對象,但是這個方法無法對消息進(jìn)行處理折柠。如果這個方法返回nil宾娜,則會走到forwardInvocation:方法。(參考自Effective Objective-C 2.0)
5.2 Forwarding and Multiple Inheritance——轉(zhuǎn)發(fā)和多重繼承
消息的轉(zhuǎn)發(fā)機(jī)制模擬了繼承機(jī)制扇售,可以將多重繼承的某些效果賦予OC程序前塔。如下圖所示嚣艇,一個對象通過轉(zhuǎn)發(fā)消息讓另一個類中的方法去響應(yīng)這條消息,看上去就像繼承了這個方法华弓。
轉(zhuǎn)發(fā)提供了通常需要多重繼承的大多數(shù)功能食零。但是,兩者之間有一個重要的區(qū)別:多重繼承在單個對象中結(jié)合了不同的功能该抒。它趨向于大型、多面的對象顶燕。另一方面凑保,轉(zhuǎn)發(fā)將不同的職責(zé)分配給不同的對象。它將問題分解為較小的對象涌攻,但以對消息發(fā)送者透明的方式關(guān)聯(lián)這些對象(怎么感覺是不透明的呢欧引,消息發(fā)送者哪知道你往哪里發(fā)的)。
5.3 Surrogate Objects——替代對象
轉(zhuǎn)發(fā)不僅可以模擬多重繼承恳谎,還可以開發(fā)成一種輕量級對象用來代替或表示更重量級的對象芝此。
在 The Objective-C Programming Language 的Remote Messaging中討論的proxy也是一種Surrogate(粗略翻了一下,沒看到因痛,應(yīng)該是在協(xié)議那一章婚苹?)。
來個例子:當(dāng)你有一個處理大量數(shù)據(jù)的對象鸵膏,然后這個對象是一個比較重量級的對象膊升,初始化設(shè)置這個對象很耗時,所以可以使用懶加載在需要它時再去加載這個對象谭企。這時廓译,可以使用輕量級的替代對象來代替這個重量級對象,這個替代對象可以做一些簡單的事情债查,但是大多數(shù)情況下非区,它只是通過forwardInvocation:將消息轉(zhuǎn)發(fā)給重量級對象。在替代對象里盹廷,當(dāng)需要重量級對象但其不存在時征绸,才會創(chuàng)建這個重量級對象。這樣就能延遲重量級對象的加載俄占。
5.4 Forwarding and Inheritance——轉(zhuǎn)發(fā)與繼承
雖然消息轉(zhuǎn)發(fā)模擬了繼承機(jī)制歹垫,但是NSObject類不會混淆這兩個玩意。也就是說颠放,自省方法像respondsToSelector: 和 isKindOfClass: 只會看繼承關(guān)系排惨,而不會去看消息轉(zhuǎn)發(fā)。
在大多數(shù)情況下碰凶,這些方法返回NO是正確的暮芭。但是如果你想用消息轉(zhuǎn)發(fā)來設(shè)置一個替代對象或者擴(kuò)展這個類的功能時鹿驼,這個轉(zhuǎn)發(fā)機(jī)制應(yīng)該像繼承機(jī)制一樣是透明的。也就是說辕宏,你要是想這個類看起來像是繼承(實際上是轉(zhuǎn)發(fā))畜晰,你需要去重寫respondsToSelector: 和 isKindOfClass:方法。
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ( [super respondsToSelector:aSelector] )
return YES;
else {
/* Here, test whether the aSelector message can *
* be forwarded to another object and whether that *
* object can respond to it. Return YES if it can. */
}
return NO;
}
另外瑞筐,instancesRespondToSelector:也應(yīng)該被重寫凄鼻。如果使用協(xié)議(應(yīng)該是看起來是使用了協(xié)議,實際還是轉(zhuǎn)發(fā))聚假,conformsToProtocol: 應(yīng)該被重寫块蚌。
相似地,如果一個對象轉(zhuǎn)發(fā)遠(yuǎn)程消息膘格,它應(yīng)該重寫這個方法methodSignatureForSelector:峭范,該方法可以返回對最終響應(yīng)所轉(zhuǎn)發(fā)消息的方法的準(zhǔn)確描述。例如瘪贱,若果一個對象來轉(zhuǎn)發(fā)消息到它的替代對象纱控,應(yīng)該這么實現(xiàn)methodSignatureForSelector:方法:
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (!signature) {
signature = [surrogate methodSignatureForSelector:selector];
}
return signature;
}
methodSignatureForSelector: 方法在NSObject類中有提及。
6 Type Encodings——類型編碼
為了協(xié)助運行時Runtime系統(tǒng)菜秦,編譯器會每個方法的返回值類型甜害、參數(shù)類型編碼成字符串,并且和方法選擇子selector相關(guān)聯(lián)球昨。由于這個編碼機(jī)制在其它一些地方也很有用唾那,所以可以使用 @encode() 編譯器指令公開使用。當(dāng)給定一個類型時褪尝,@encode() 方法可以返回這個類型的編碼字符串闹获。這個類型可以是基本類型,如int河哑、指針避诽,也可以使其它類型,一切可以使用sizeof()運算符的類型璃谨。
char *buf1 = @encode(int **);
char *buf2 = @encode(struct key);
char *buf3 = @encode(Rectangle);
具體還是見原文檔吧沙庐。
7 Declared Properties——屬性聲明
終于到最后一章了...
當(dāng)編譯器碰到屬性聲明(見The Objective-C Programming Language中的Declared Properties)時,編譯器會生成與類佳吞、分類拱雏、協(xié)議相關(guān)聯(lián)的描述性元數(shù)據(jù)(metadata)。
你可以使用函數(shù)訪問這個元數(shù)據(jù):可以通過名稱查找一個類或協(xié)議里的屬性底扳;獲取屬性的類型編碼铸抑;將屬性列表以C字符串?dāng)?shù)組的形式拷貝出來。
7.1 Property Type and Functions——屬性類型與相關(guān)函數(shù)
The Property structure defines an opaque handle to a property descriptor.
Property structure定義了屬性描述符的不透明句柄衷模。
typedef struct objc_property *Property;
(1)使用 class_copyPropertyList 和 protocol_copyPropertyList 函數(shù) 分別來檢索類(包含被加載的分類)和協(xié)議的屬性:
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
下面是例子:
這是一個類:
@interface Lender : NSObject {
float alone;
}
@property float alone;
@end
獲取它的屬性列表:
id LenderClass = objc_getClass("Lender");
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
(2)使用property_getName來獲取屬性名
const char *property_getName(objc_property_t property)
(3)使用 class_getProperty 獲取屬性在類里的引用鹊汛, protocol_getProperty 獲取屬性在協(xié)議里的引用
objc_property_t class_getProperty(Class cls, const char *name)
objc_property_t protocol_getProperty(Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty)
(4)使用 property_getAttributes 函數(shù)獲取一個屬性的名稱和類型編碼
const char *property_getAttributes(objc_property_t property)
(5)總結(jié)蒲赂,綜合使用,利用運行時系統(tǒng)打印一個類的關(guān)聯(lián)屬性:
id LenderClass = objc_getClass("Lender");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}
7.2 Property Type String——屬性類型字符串
你可以使用property_getAttributes函數(shù)獲取屬性的名稱刁憋、類型編碼以及一些其它特性滥嘴。
這個字符串以T開頭,后面跟著類型編碼至耻,然后是逗號若皱,然后以V開頭,跟著實例變量的名稱尘颓。在這兩個之間走触,有以逗號分隔的屬性修飾符的類型編碼。
表格具體見文檔泥耀,這里寫的是屬性修飾符(如copy)的類型編碼饺汹。
7.2 Property Attribute Description Examples——屬性特性描述例子
這里有很多例子蛔添,可以參考源文檔痰催。