Objective-C Runtime Programming Guide——蘋果文檔翻譯與筆記

好久沒寫簡書了,一是因為懶,二也是因為懶吧...

本文主要翻譯了 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)行交互:

  1. 通過OC源碼傀蚌;
  2. 通過Foundation framework中的NSObject類(內(nèi)省方法)基显;
  3. 直接調(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)中查詢信息:

  1. isKindOfClass: 是否是某一個類或其子類
  2. isMemberOfClass: 是否是某一個類
  3. respondsToSelector: 是否能夠響應(yīng)某個方法
  4. conformsToProtocol: 是否遵守了某個協(xié)議
  5. 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)包含兩個基本元素

  1. superclass父類的指針
  2. 一個類調(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指針可以讓對象去訪問它所屬的類寇钉,并可以通過這個類訪問其繼承的所有類刀疙。

消息傳遞的結(jié)構(gòu)

當(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ù)

  1. 接收消息的對象
  2. 方法的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ù)集成泞边。

NSBundle類參考

推測:這個動態(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: 方法需要做這兩點:

  1. 確定這個消息要去哪里
  2. 將原始參數(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è)計開辟了可能性:

  1. 它可以當(dāng)做一個未識別消息的分發(fā)中心,將其打包發(fā)送給其它不同的接收者裕偿;
  2. 或者它可以當(dāng)做一個中轉(zhuǎn)站洞慎,將所有消息發(fā)送到同一個目的地;
  3. 它還可以將一種類型的消息轉(zhuǎn)換為另一種嘿棘;
  4. 它可以將一些消息“吞”掉劲腿,這樣這些消息既沒有響應(yīng)也不會有報錯;
  5. 它可以將多個消息合并為一個(這個不太懂鸟妙,多個方法其實本質(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)這條消息,看上去就像繼承了這個方法华弓。

image

轉(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——屬性特性描述例子

這里有很多例子蛔添,可以參考源文檔痰催。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市迎瞧,隨后出現(xiàn)的幾起案子夸溶,更是在濱河造成了極大的恐慌,老刑警劉巖凶硅,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缝裁,死亡現(xiàn)場離奇詭異,居然都是意外死亡足绅,警方通過查閱死者的電腦和手機(jī)捷绑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氢妈,“玉大人粹污,你說我怎么就攤上這事∈琢浚” “怎么了壮吩?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長加缘。 經(jīng)常有香客問我鸭叙,道長,這世上最難降的妖魔是什么拣宏? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任沈贝,我火速辦了婚禮,結(jié)果婚禮上勋乾,老公的妹妹穿的比我還像新娘缀程。我一直安慰自己搜吧,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布杨凑。 她就那樣靜靜地躺著滤奈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撩满。 梳的紋絲不亂的頭發(fā)上蜒程,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音伺帘,去河邊找鬼昭躺。 笑死,一個胖子當(dāng)著我的面吹牛伪嫁,可吹牛的內(nèi)容都是我干的领炫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼张咳,長吁一口氣:“原來是場噩夢啊……” “哼帝洪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起脚猾,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤葱峡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后龙助,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砰奕,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年提鸟,在試婚紗的時候發(fā)現(xiàn)自己被綠了军援。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡称勋,死狀恐怖胸哥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铣缠,我是刑警寧澤烘嘱,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蝗蛙,受9級特大地震影響蝇庭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捡硅,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一哮内、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦北发、人聲如沸纹因。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瞭恰。三九已至,卻和暖如春狱庇,著一層夾襖步出監(jiān)牢的瞬間惊畏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工密任, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留颜启,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓浪讳,卻偏偏與公主長得像缰盏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淹遵,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容