Runtime 的理解

Runtime是深入學習OC的必經(jīng)之路吉嚣,所以花了一些時間研究了一下梢薪。

一、介紹RunTime(運行時):

OC 語言是一門動態(tài)語言尝哆,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了運行時來處理秉撇。

對于OC來說,這個運行時系統(tǒng)就像一個操作系統(tǒng)一樣:它讓所有的工作可以正常的運行秋泄。Runtime基本上是用C和匯編寫的琐馆,這個庫使得C語言有了面向?qū)ο蟮哪芰Α?/p>

在Runtime中,對象可以用C語言中的結(jié)構(gòu)體表示恒序,而方法可以用C函數(shù)來實現(xiàn)瘦麸,另外再加上了一些額外的特性。這些結(jié)構(gòu)體和函數(shù)被runtime函數(shù)封裝后歧胁,讓OC的面向?qū)ο缶幊套優(yōu)榭赡堋?/p>

找出方法的最終執(zhí)行代碼:當程序執(zhí)行[object doSomething]時滋饲,會向消息接收者(object)發(fā)送一條消息(doSomething),runtime會根據(jù)消息接收者是否能響應(yīng)該消息而做出不同的反應(yīng)喊巍。


二屠缭、類與對象的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

OC類是由Class類型來表示的,它實際上是一個指

向objc_class結(jié)構(gòu)體的指針崭参。

typedef struct object_class *Class

其定義如下:

查看objc/runtime.h中objc_class結(jié)構(gòu)體的定義如下:

struct object_class{? ?

Class isa OBJC_ISA_AVAILABILITY;

#if!__OBJC2__

Class super_class? ? ? ? ? ? ? ? ? ? ? ?

OBJC2_UNAVAILABLE;// 父類constchar*name? ? ? ? ? ? ? ?

OBJC2_UNAVAILABLE;// 類名longversion

OBJC2_UNAVAILABLE;// 類的版本信息呵曹,默認為0longinfo? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 類信息,供運行期使用的一些位標識longinstance_size? ? ? ? ? ? ? ? ?? OBJC2_UNAVAILABLE;// 該類的實例變量大小structobjc_ivar_list *ivars? ? ? ? ? ? OBJC2_UNAVAILABLE;// 該類的成員變量鏈表structobjc_method_list *methodLists? ? OBJC2_UNAVAILABLE;// 方法定義的鏈表structobjc_cache *cache? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 方法緩存structobjc_protocol_list *protocols? ? OBJC2_UNAVAILABLE;// 協(xié)議鏈表#endif}OBJC2_UNAVAILABLE;


其執(zhí)行過程:

NSArray *array = [[NSArray alloc] init];

objc_object

objc_object是表示一個類的實例的結(jié)構(gòu)體

它的定義如下(objc/objc.h):

structobjc_object{? ? Class isa OBJC_ISA_AVAILABILITY;};typedefstructobjc_object*id;

可以看到,這個結(jié)構(gòu)體只有一個字體奄喂,即指向其類的isa指針之剧。這

樣,當我們向一個Objective-C對象發(fā)送消息時砍聊,運行時庫會根據(jù)

實例對象的isa指針找到這個實例對象所屬的類背稼。Runtime庫會在類

的方法列表及父類的方法列表中去尋找與消息對應(yīng)的selector指向

的方法,找到后即運行這個方法玻蝌。

元類(Meta Class)

meta-class是一個類對象的類蟹肘。

在上面我們提到,所有的類自身也是一個對象俯树,我們可以向這個對象發(fā)送消息(即調(diào)用類方法)帘腹。

既然是對象,那么它也是一個objc_object指針许饿,它包含一個指向其類的一個isa指針阳欲。那么,這個isa指針指向什么呢陋率?

為了調(diào)用類方法球化,這個類的isa指針必須指向一個包含這些類方法的一個objc_class結(jié)構(gòu)體。這就引出了meta-class的概念瓦糟,meta-class中存儲著一個類的所有類方法筒愚。

所以,調(diào)用類方法的這個類對象的isa指針指向的就是meta-class

當我們向一個對象發(fā)送消息時菩浙,runtime會在這個對象所屬的這個類的方法列表中查找方法巢掺;而向一個類發(fā)送消息時,會在這個類的meta-class的方法列表中查找劲蜻。

再深入一下陆淀,meta-class也是一個類,也可以向它發(fā)送一個消息先嬉,那么它的isa又是指向什么呢轧苫?為了不讓這種結(jié)構(gòu)無限延伸下去,Objective-C的設(shè)計者讓所有的meta-class的isa指向基類的meta-class坝初,以此作為它們的所屬類浸剩。

即钾军,任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己的所屬類鳄袍,而基類的meta-class的isa指針是指向它自己。

通過上面的描述吏恭,再加上對objc_class結(jié)構(gòu)體中super_class指針的分析拗小,我們就可以描繪出類及相應(yīng)meta-class類的一個繼承體系了,如下代碼

Snip20160501_1.png

Category

Category是表示一個指向分類的結(jié)構(gòu)體的指針樱哼,其定義如下:

typedefstructobjc_category*Categorystructobjc_category{char*category_name? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 分類名char*class_name? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;// 分類所屬的類名structobjc_method_list*instance_methods? OBJC2_UNAVAILABLE;// 實例方法列表structobjc_method_list*class_methods? ? ? OBJC2_UNAVAILABLE;// 類方法列表structobjc_protocol_list*protocols? ? ? ? OBJC2_UNAVAILABLE;// 分類所實現(xiàn)的協(xié)議列表}

這個結(jié)構(gòu)體主要包含了分類定義的實例方法與類方法哀九,其中instance_methods列表是objc_class中方法列表的一個子集剿配,而class_methods列表是元類方法列表的一個子集。

可發(fā)現(xiàn)阅束,類別中沒有ivar成員變量指針呼胚,也就意味著:類別中不能夠添加實例變量和屬性

structobjc_ivar_list*ivars? ? ? ? ? ? OBJC2_UNAVAILABLE;// 該類的成員變量鏈表

三、runtime關(guān)聯(lián)對象

我們先看看關(guān)聯(lián)API息裸,只有這三個API蝇更,使用也是非常簡單的:

1.設(shè)置關(guān)聯(lián)值

參數(shù)說明:

object:與誰關(guān)聯(lián),通常是傳self

key:唯一鍵呼盆,在獲取值時通過該鍵獲取年扩,通常是使用static

const void *來聲明

value:關(guān)聯(lián)所設(shè)置的值

policy:內(nèi)存管理策略,比如使用copy

voidobjc_setAssociatedObject(idobject,constvoid*key, idvalue, objc _AssociationPolicy policy)

2.獲取關(guān)聯(lián)值

參數(shù)說明:

object:與誰關(guān)聯(lián)访圃,通常是傳self厨幻,在設(shè)置關(guān)聯(lián)時所指定的與哪個對象關(guān)聯(lián)的那個對象

key:唯一鍵,在設(shè)置關(guān)聯(lián)時所指定的鍵

idobjc_getAssociatedObject(idobject,constvoid*key)

3.取消關(guān)聯(lián)

voidobjc_removeAssociatedObjects(idobject)

關(guān)聯(lián)策略

使用場景:

可以在類別中添加屬性

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy){OBJC_ASSOCIATION_ASSIGN =0,// 表示弱引用關(guān)聯(lián)腿时,通常是基本數(shù)據(jù)類型OBJC_ASSOCIATION_RETAIN_NONATOMIC =1,// 表示強引用關(guān)聯(lián)對象况脆,是線程安全的OBJC_ASSOCIATION_COPY_NONATOMIC =3,// 表示關(guān)聯(lián)對象copy,是線程安全的OBJC_ASSOCIATION_RETAIN =01401,// 表示強引用關(guān)聯(lián)對象批糟,不是線程安全的OBJC_ASSOCIATION_COPY =01403// 表示關(guān)聯(lián)對象copy漠另,不是線程安全的};

四、方法與消息

1跃赚、SEL

SEL又叫選擇器笆搓,是表示一個方法的selector的指針,其定義如下:

typedefstructobjc_selector *SEL纬傲;

方法的selector用于表示運行時方法的名字满败。Objective-C在編譯時,會依據(jù)每一個方法的名字叹括、參數(shù)序列算墨,生成一個唯一的整型標識(Int類型的地址),這個標識就是SEL汁雷。

兩個類之間净嘀,只要方法名相同,那么方法的SEL就是一樣的侠讯,每一個方法都對應(yīng)著一個SEL挖藏。所以在Objective-C同一個類(及類的繼承體系)中,不能存在2個同名的方法厢漩,即使參數(shù)類型不同也不行

如在某一個類中定義以下兩個方法: 錯誤

- (void)setWidth:(int)width;- (void)setWidth:(double)width;

當然膜眠,不同的類可以擁有相同的selector,這個沒有問題。不同類的實例對象執(zhí)行相同的selector時宵膨,會在各自的方法列表中去根據(jù)selector去尋找自己對應(yīng)的IMP架谎。

工程中的所有的SEL組成一個Set集合,如果我們想到這個方法集合中查找某個方法時辟躏,只需要去找到這個方法對應(yīng)的SEL就行了谷扣,SEL實際上就是根據(jù)方法名hash化了的一個字符串,而對于字符串的比較僅僅需要比較他們的地址就可以了捎琐,可以說速度上無語倫比抑钟!

本質(zhì)上,SEL只是一個指向方法的指針(準確的說野哭,只是一個根據(jù)方法名hash化了的KEY值在塔,能唯一代表一個方法),它的存在只是為了加快方法的查詢速度拨黔。

通過下面三種方法可以獲取SEL:

a蛔溃、sel_registerName函數(shù)

b、Objective-C編譯器提供的@selector()

c篱蝇、NSSelectorFromString()方法

2贺待、IMP

IMP實際上是一個函數(shù)指針,指向方法實現(xiàn)的地址零截。

其定義如下:

id (*IMP)(id, SEL,...)

第一個參數(shù):是指向self的指針(如果是實例方法麸塞,則是類實例的內(nèi)存地址;如果是類方法涧衙,則是指向元類的指針)

第二個參數(shù):是方法選擇器(selector)

接下來的參數(shù):方法的參數(shù)列表哪工。

前面介紹過的SEL就是為了查找方法的最終實現(xiàn)IMP的。由于每個方法對應(yīng)唯一的SEL弧哎,因此我們可以通過SEL方便快速準確地獲得它所對應(yīng)的IMP雁比,查找過程將在下面討論。取得IMP后撤嫩,我們就獲得了執(zhí)行這個方法代碼的入口點偎捎,此時,我們就可以像調(diào)用普通的C語言函數(shù)一樣來使用這個函數(shù)指針了序攘。

3茴她、Method

Method用于表示類定義中的方法,則定義如下:

typedef struct objc_method *Methodstructobjc_method{

SEL method_name? ? ? OBJC2_UNAVAILABLE; // 方法名

char *method_types? OBJC2_UNAVAILABLE;

IMP method_imp? ? ? OBJC2_UNAVAILABLE; // 方法實現(xiàn)

}

我們可以看到該結(jié)構(gòu)體中包含一個SEL和IMP程奠,實際上相當于在SEL和IMP之間作了一個映射丈牢。有了SEL,我們便可以找到對應(yīng)的IMP梦染,從而調(diào)用方法的實現(xiàn)代碼赡麦。

4朴皆、方法調(diào)用流程

Snip20160501_2.png

在Objective-C中帕识,消息直到運行時才綁定到方法實現(xiàn)上泛粹。編譯器會將消息表達式[receiver message]轉(zhuǎn)化為一個消息函數(shù)的調(diào)用,即objc_msgSend肮疗。這個函數(shù)將消息接收者和方法名作為其基礎(chǔ)參數(shù)晶姊,如以下所示

objc_msgSend(receiver, selector)

如果消息中還有其它參數(shù),則該方法的形式如下所示:

objc_msgSend(receiver, selector, arg1, arg2,...)

這個函數(shù)完成了動態(tài)綁定的所有事情:

a伪货、首先它找到selector對應(yīng)的方法實現(xiàn)们衙。因為同一個方法可

能在不同的類中有不同的實現(xiàn),所以我們需要依賴于接收者的類

來找到的確切的實現(xiàn)碱呼。

b蒙挑、調(diào)用方法實現(xiàn),并將接收者對象及方法的所有參數(shù)傳給它愚臀。

c忆蚀、最后,它將實現(xiàn)返回的值作為它自己的返回值姑裂。

消息的關(guān)鍵在于我們前面章節(jié)討論過的結(jié)構(gòu)體objc_class馋袜,這個結(jié)構(gòu)體有兩個字段是我們在分發(fā)消息的關(guān)注的:

-> 指向父類的指針

-> 個類的方法分發(fā)表,即methodLists舶斧。

當我們創(chuàng)建一個新對象時欣鳖,先為其分配內(nèi)存,并初始化其成員變量茴厉。其中isa指針也會被初始化泽台,讓對象可以訪問類及類的繼承體系。

下圖演示了這樣一個消息的基本框架:

當消息發(fā)送給一個對象時首先從運行時系統(tǒng)緩存使用過的方法中尋找矾缓。

如果找到师痕,執(zhí)行該方法,如未找到繼續(xù)執(zhí)行下面的步驟

objc_msgSend通過對象的isa指針獲取到類的結(jié)構(gòu)體,然后在方法分發(fā)表里面查找方法的selector而账。

如果沒有找到selector胰坟,objc_msgSend結(jié)構(gòu)體中的指向父類的指針找到其父類,并在父類的分發(fā)表里面查找方法的selector泞辐。

依此笔横,會一直沿著類的繼承體系到達NSObject類。一旦定位到selector咐吼,函數(shù)會就獲取到了實現(xiàn)的入口點吹缔,并傳入相應(yīng)的參數(shù)來執(zhí)行方法的具體實現(xiàn),并將該方法添加進入緩存中如果最后沒有定位到selector,則會走消息轉(zhuǎn)發(fā)流程锯茄,這個我們在后面討論厢塘。

5茶没、消息轉(zhuǎn)發(fā)

當一個對象能接收一個消息時,就會走正常的方法調(diào)用流程晚碾。但如果一個對象無法接收指定消息時抓半,又會發(fā)生什么事呢?默認情況下格嘁,如果是以[object message]的方式調(diào)用方法笛求,如果object無法響應(yīng)message消息時,編譯器會報錯糕簿。但如果是以perform…的形式來調(diào)用探入,則需要等到運行時才能確定object是否能接收message消息。如果不能懂诗,則程序崩潰蜂嗽。

Snip20160501_3.png

通常,當我們不能確定一個對象是否能接收某個消息時殃恒,會先調(diào)用respondsToSelector:來判斷一下植旧。如下代碼所示:

if([selfrespondsToSelector:@selector(method)]){[self performSelector:@selector(method)];}

不過,我們這邊想討論下不使用respondsToSelector:判斷的情況芋类。這才是我們這一節(jié)的重點隆嗅。

當一個對象無法接收某一消息時,就會啟動所謂“消息轉(zhuǎn)發(fā)(message forwarding)”機制侯繁,通過這一機制胖喳,我們可以告訴對象如何處理未知的消息。默認情況下贮竟,對象接收到未知的消息丽焊,會導致程序崩潰,通過控制臺咕别,我們可以看到以下異常信息:

這段異常信息實際上是由NSObject的“doesNotRecognizeSelector”方法拋出的技健。不過,我們可以采取一些措施惰拱,讓我們的程序執(zhí)行特定的邏輯雌贱,而避免程序的崩潰。

消息轉(zhuǎn)發(fā)機制基本上分為三個步驟:

1>偿短、動態(tài)方法解析

2>欣孤、備用接收者

3>、完整轉(zhuǎn)發(fā)

消息的轉(zhuǎn)發(fā)流程圖:

Snip20160501_5.png

動態(tài)方法解析

對象在接收到未知的消息時昔逗,首先會調(diào)用所屬類的類方法

+resolveInstanceMethod:(實例方法)或者

+resolveClassMethod:(類方法)降传。

在這個方法中,我們有機會為該未知消息新增一個“處理方法”勾怒,通過運行時class_addMethod函數(shù)動態(tài)添加到類里面就可以了婆排。

這種方案更多的是為了實現(xiàn)@dynamic屬性声旺。

備用接收者

-(id)forwardingTargetForSelector:(SEL)aSelector

如果在上一步無法處理消息,則Runtime會繼續(xù)調(diào)以下方法:

如果一個對象實現(xiàn)了這個方法段只,并返回一個非nil的結(jié)果腮猖,則這個對象會作為消息的新接收者,且消息會被分發(fā)到這個對象翼悴。當然這個對象不能是self自身缚够,否則就是出現(xiàn)無限循環(huán)幔妨。當然鹦赎,如果我們沒有指定相應(yīng)的對象來處理aSelector,則應(yīng)該調(diào)用父類的實現(xiàn)來返回結(jié)果误堡。

這一步合適于我們只想將消息轉(zhuǎn)發(fā)到另一個能處理該消息的對象上古话。但這一步無法對消息進行處理,如操作消息的參數(shù)和返回值锁施。

完整消息轉(zhuǎn)發(fā)

如果在上一步還不能處理未知消息陪踩,則唯一能做的就是啟用完整的消息轉(zhuǎn)發(fā)機制了。

我們首先要通過,指定方法簽名悉抵,若返回nil肩狂,則表示不處理。

如下代碼:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{if([NSStringFromSelector(aSelector)isEqualToString:@"testInstanceMethod"]){return[NSMethodSignaturesignatureWithObjcTypes:"v@:"];? }return[supermethodSignatureForSelector:aSelector];}

若返回方法簽名姥饰,則會進入下一步調(diào)用以下方法傻谁,對象會創(chuàng)建一個表示消息的NSInvocation對象,把與尚未處理的消息有關(guān)的全部細節(jié)都封裝在anInvocation中列粪,包括selector审磁,目標(target)和參數(shù)。

我們可以在forwardInvocation方法中選擇將消息轉(zhuǎn)發(fā)給其它對象岂座。我們可以通過anInvocation對象做很多處理态蒂,比如修改實現(xiàn)方法,修改響應(yīng)對象等.

如下所示:

- (void)forwardInvovation:(NSInvocation)anInvocation{? ? [anInvocationinvokeWithTarget:_helper];? ? [anInvocationsetSelector:@selector(run)];? ? [anInvocationinvokeWithTarget:self];}

五费什、Method Swizzling

1.Swizzling原理

在Objective-C中調(diào)用一個方法钾恢,其實是向一個對象發(fā)送消息,而查找消息的唯一依據(jù)是selector的名字鸳址。所以瘩蚪,我們可以利用Objective-C的runtime機制,實現(xiàn)在運行時交換selector對應(yīng)的方法實現(xiàn)以達到我們的目的氯质。

每個類都有一個方法列表募舟,存放著selector的名字和方法實現(xiàn)的映射關(guān)系。IMP有點類似函數(shù)指針闻察,指向具體的Method實現(xiàn)

我們先看看SEL與IMP之間的關(guān)系圖:

Snip20160501_6.png

從上圖可以看出來拱礁,每一個SEL與一個IMP一一對應(yīng)琢锋,正常情況下通過SEL可以查找到對應(yīng)消息的IMP實現(xiàn)。

但是呢灶,現(xiàn)在我們要做的就是把鏈接線解開吴超,然后連到我們自定義的函數(shù)的IMP上。當然鸯乃,交換了兩個SEL的IMP鲸阻,還是可以再次交換回來了。交換后變成這樣的缨睡,如下圖

Snip20160501_7.png

從圖中可以看出鸟悴,我們通過swizzling特性,將selectorC的方法實現(xiàn)IMPc與selectorN的方法實現(xiàn)IMPn交換了奖年,當我們調(diào)用selectorC细诸,也就是給對象發(fā)送selectorC消息時,所查找到的對應(yīng)的方法實現(xiàn)就是IMPn而不是IMPc了陋守。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末震贵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子水评,更是在濱河造成了極大的恐慌猩系,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件中燥,死亡現(xiàn)場離奇詭異寇甸,居然都是意外死亡,警方通過查閱死者的電腦和手機褪那,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門幽纷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人博敬,你說我怎么就攤上這事友浸。” “怎么了偏窝?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵收恢,是天一觀的道長。 經(jīng)常有香客問我祭往,道長伦意,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任硼补,我火速辦了婚禮驮肉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘已骇。我一直安慰自己离钝,他們只是感情好票编,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卵渴,像睡著了一般慧域。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浪读,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天昔榴,我揣著相機與錄音,去河邊找鬼碘橘。 笑死互订,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蛹屿。 我是一名探鬼主播屁奏,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼岩榆,長吁一口氣:“原來是場噩夢啊……” “哼错负!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勇边,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤犹撒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后粒褒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體识颊,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年奕坟,在試婚紗的時候發(fā)現(xiàn)自己被綠了祥款。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡月杉,死狀恐怖刃跛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苛萎,我是刑警寧澤桨昙,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站腌歉,受9級特大地震影響蛙酪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翘盖,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一桂塞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧馍驯,春花似錦阁危、人聲如沸炊甲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卿啡。三九已至,卻和暖如春菱父,著一層夾襖步出監(jiān)牢的瞬間颈娜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工浙宜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留官辽,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓粟瞬,卻偏偏與公主長得像同仆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子裙品,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉俗批,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評論 0 9
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現(xiàn)在哪呢市怎?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,192評論 0 7
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 732評論 0 2
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 758評論 0 1
  • 前言 runtime其實在我們?nèi)粘i_發(fā)過程中很少使用到岁忘,尤其是像我現(xiàn)在比較初級的程序猿就更用不到了。但是去面試很多...
    WolfTin閱讀 622評論 0 2