runtime進(jìn)行曲添诉,objc_msgSend的前世今生(一)

runtime小序曲一文中舉出了runtime的三種應(yīng)用方式:

  • Objective-C源代碼,以objc_msgSend方法舉例旺遮。
  • NSObject的方法赵讯。
  • Runtime的函數(shù)。

本文將就第一種方式中的objc_msgSend方法展開講解耿眉。
學(xué)習(xí)進(jìn)度:

一、objc_msgSend的兩種姿勢(shì)

很容易想到斤寇,OC中的兩種方法調(diào)用的姿勢(shì):實(shí)例方法和類方法桶癣。下面我們通過(guò)一個(gè)簡(jiǎn)單樣例的clang處理后的代碼看一下。

// OC代碼
// main.m
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface A : NSObject
@property (nonatomic, assign) NSInteger a;
- (void)b;
+ (void)c;
@end
@implementation A
- (void)b {
    NSLog(@"b");
}
+ (void)c {
    NSLog(@"c");
}
@end
int main(int argc, char * argv[]) {
    A *aObject = [[A alloc] init];
    // 實(shí)例方法調(diào)用
    [aObject b];
    // 類方法調(diào)用
    [A c];
}

通過(guò)xcrun -sdk iphonesimulator9.3 clang -rewrite-objc main.m將其轉(zhuǎn)換為編譯后的偽代碼娘锁,即運(yùn)行時(shí)執(zhí)行的代碼的偽代碼(代碼比較多牙寞,只列出我們想要的)。

// A類定義
typedef struct objc_object A;
// objc_getClass方法
struct objc_class *objc_getClass(const char *);
// sel_registerName方法
SEL sel_registerName(const char *str) __attribute__((availability(ios,introduced=2.0)));

// 對(duì)應(yīng)上述main函數(shù)
int main(int argc, char * argv[]) {
    A *aObject = ((A *(*)(id, SEL))(void *)objc_msgSend)((id)((A *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("A"), sel_registerName("alloc")), sel_registerName("init"));
    // 實(shí)例方法調(diào)用
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)aObject, sel_registerName("b"));
    // 類方法調(diào)用
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("A"), sel_registerName("c"));
}

將上述實(shí)例方法調(diào)用和類方法調(diào)用的強(qiáng)制轉(zhuǎn)換干掉之后看下莫秆。

實(shí)例方法

objc_msgSend(aObject, sel_registerName("b"));

可知间雀,aObject是一個(gè)objc_object結(jié)構(gòu)體,sel_registerName返回值為SEL镊屎。所以惹挟,這句話的意思大致是:向一個(gè)objc_object發(fā)送一個(gè)SEL。當(dāng)然缝驳,具體怎么發(fā)送的這里先不談连锯。

類方法

objc_msgSend(objc_getClass("A"), sel_registerName("c"));

可知,objc_getClass返回值為objc_class用狱,sel_registerName返回值為SEL运怖。所以,這句話的意思大致是:向一個(gè)objc_class發(fā)送一個(gè)SEL夏伊。當(dāng)然摇展,具體怎么發(fā)送的這里先不談。下文會(huì)說(shuō)溺忧。

本節(jié)過(guò)后咏连,大概有兩個(gè)疑問(wèn):
1、objc_object鲁森、objc_class祟滴、SEL分別是什么東西?
2歌溉、objc_msgSend到底如何工作踱启?

二、objc_object和objc_class

上一節(jié)留了兩個(gè)問(wèn)題研底,這里先回答第一個(gè)問(wèn)題的一部分埠偿,即objc_object、objc_class是什么榜晦?可以參照runtime源碼冠蒋。在objc.h和runtime.h里面分別可以找到objc_object和objc_class的實(shí)現(xiàn)。

objc_object

// 在objc.h中找到相關(guān)代碼
typedef struct objc_class *Class;
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

動(dòng)態(tài)類型id其實(shí)就是一個(gè)objc_object乾胶。

可以看出一個(gè)類的實(shí)例抖剿,即一個(gè)對(duì)象朽寞,其實(shí)在runtime時(shí)刻是一個(gè)objc_class結(jié)構(gòu)體,而結(jié)構(gòu)體里面只有一個(gè)指向objc_class的指針isa斩郎。哎吆脑融,objc_class好像在哪里見(jiàn)過(guò)?對(duì)缩宜,就是上面提到的調(diào)用類方法使用的結(jié)構(gòu)體肘迎,下面看一下它的結(jié)構(gòu)。

objc_class

// 在runtime.h中找到相關(guān)代碼
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

objc_class的結(jié)構(gòu)體的東西就比較多了锻煌,因?yàn)楝F(xiàn)在討論的是調(diào)用類的方法妓布,所以我們只關(guān)注三個(gè)東西isa、super_class和objc_method_list宋梧。
isa指向一個(gè)objc_class對(duì)象匣沼,而super_class比較容易理解,即指向這個(gè)類的父類捂龄。而objc_method_list會(huì)在下一節(jié)和SEL一起講解释涛。

本節(jié)并沒(méi)有講解一些東西,只是說(shuō)了下兩個(gè)結(jié)構(gòu)體的實(shí)現(xiàn)倦沧,讓大家對(duì)isa唇撬、super_class有一個(gè)概念。本節(jié)過(guò)后刀脏,大家的疑問(wèn)應(yīng)該變多了局荚,結(jié)合一中疑問(wèn)超凳,大概以下幾個(gè):
1愈污、objc_method_list、SEL轮傍。
2暂雹、isa、super_class有什么用创夜?怎么用杭跪?
3、objc_msgSend到底如何工作驰吓?

三涧尿、objc_method、SEL和IMP

二中第一個(gè)疑問(wèn)是objc_method_list檬贰、SEL姑廉,而引入objc_method_list是objc_method的列表,所以我們不研究objc_method_list翁涤,改為研究objc_method和SEL桥言,而objc_method結(jié)構(gòu)體中還有一個(gè)IMP萌踱,與本節(jié)內(nèi)容息息相關(guān),所以以objc_method号阿、SEL和IMP為中心講解并鸵。

objc_method

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

可知,OC中每一個(gè)方法都是如上的結(jié)構(gòu)體扔涧,里面的兩個(gè)關(guān)鍵字段method_name和method_imp共同為方法的查找和使用服務(wù)园担。

SEL
從SEL類型的成員為method_name可以知道,SEL大概代表一個(gè)方法的名字扰柠,可以通過(guò)以下方式檢驗(yàn)粉铐。

// OC代碼
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface A : NSObject
@property (nonatomic, assign) NSInteger a;
- (void)b;
+ (void)c;
@end
@implementation A
- (void)b {
}
+ (void)c {
    NSLog(@"%s", @selector(b));
}
@end
int main(int argc, char * argv[]) {
    [A c];
}

// 輸出
2016-12-29 15:23:03.850 block[57622:533311] b

IMP
SEL的作用很容易理解,即想找到想要的objc_method結(jié)構(gòu)體卤档,需要通過(guò)SEL來(lái)遍歷蝙泼,那么,IMP是什么呢劝枣?一般來(lái)說(shuō)汤踏,通過(guò)SEL找到想要的objc_method,下一步就是調(diào)用方法的實(shí)現(xiàn)了舔腾,objc_method結(jié)構(gòu)體中唯一有可能和方法實(shí)現(xiàn)相關(guān)的就是IMP了溪胶。所以,IMP是一個(gè)函數(shù)指針稳诚,指向objc_method對(duì)應(yīng)方法的實(shí)現(xiàn)部分哗脖。

objc_method中的method_types指的是方法的返回值和參數(shù)。以返回值開始扳还,依次把參數(shù)拼在后面才避,比如"i@",即為返回值為int類型氨距,參數(shù)為一個(gè)對(duì)象桑逝,參照對(duì)照表

簡(jiǎn)單樣例

// 考慮到只用文字描述有點(diǎn)空洞俏让,這里通過(guò)class_addMethod方法的使用做個(gè)樣例
//先看下class_addMethod定義楞遏,幾個(gè)參數(shù)容易理解。cls為需要增加方法的類首昔,后三個(gè)參數(shù)對(duì)應(yīng)objc_method結(jié)構(gòu)體中的幾個(gè)成員寡喝。
OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);

// OC代碼
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface A : NSObject
@property (nonatomic, assign) NSInteger a;
- (void)b;
@end
@implementation A
- (void)b {
}
@end
int c(NSString *str) {
    NSLog(@"c");
    return 0;
}
int main(int argc, char * argv[]) {
    class_addMethod([A class], @selector(c:), (IMP)c, "i@");
    A *aObject = [[A alloc] init];
    [aObject performSelector:@selector(c:)];
}

// 輸出,可見(jiàn)完成了方法c的調(diào)用勒奇。
2016-12-29 15:51:17.931 block[60624:567679] c

本節(jié)內(nèi)容大致到這预鬓,SEL、IMP你應(yīng)該搞懂了撬陵,現(xiàn)在只剩下兩個(gè)問(wèn)題:
1珊皿、isa网缝、super_class有什么用?怎么用蟋定?
2粉臊、objc_msgSend到底如何工作?

四驶兜、objc_msgSend工作原理和實(shí)例方法調(diào)用

1扼仲、objc_msgSend工作原理

偽代碼

// 首先看一下objc_msgSend的方法實(shí)現(xiàn)的偽代碼
id objc_msgSend(id self, SEL op, ...) {
   if (!self) return nil;
   // 關(guān)鍵代碼(a)
   IMP imp = class_getMethodImplementation(self->isa, SEL op);
   imp(self, op, ...); // 調(diào)用這個(gè)函數(shù),偽代碼...
}
// 查找IMP
IMP class_getMethodImplementation(Class cls, SEL sel) {
    if (!cls || !sel) return nil;
    IMP imp = lookUpImpOrNil(cls, sel);
    if (!imp) {
      ... // 執(zhí)行動(dòng)態(tài)綁定
    }
    IMP imp = lookUpImpOrNil(cls, sel);
    if (!imp) return _objc_msgForward; // 這個(gè)是用于消息轉(zhuǎn)發(fā)的
    return imp;
}
// 遍歷繼承鏈抄淑,查找IMP
IMP lookUpImpOrNil(Class cls, SEL sel) {
    if (!cls->initialize()) {
        _class_initialize(cls);
    }
    Class curClass = cls;
    IMP imp = nil;
    do { // 先查緩存,緩存沒(méi)有時(shí)重建,仍舊沒(méi)有則向父類查詢
        if (!curClass) break;
        if (!curClass->cache) fill_cache(cls, curClass);
        imp = cache_getImp(curClass, sel);
        if (imp) break;
    } while (curClass = curClass->superclass); // 關(guān)鍵代碼(b)
    return imp;
}

分析
首先在Class中的緩存查找imp(沒(méi)緩存則初始化緩存)屠凶,如果沒(méi)找到,則向父類的Class查找肆资。如果一直查找到根類仍舊沒(méi)有實(shí)現(xiàn)矗愧,則用_objc_msgForward函數(shù)指針代替imp。最后郑原,執(zhí)行這個(gè)imp唉韭。

2、實(shí)例方法調(diào)用

代碼

// 實(shí)例方法調(diào)用犯犁,參照一
objc_msgSend(aObject, sel_registerName("b"));

// 參照二中實(shí)例對(duì)象的結(jié)構(gòu)
typedef struct objc_class *Class;
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

// 順便給出objc_class結(jié)構(gòu)
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

分析
結(jié)合關(guān)鍵代碼(a)属愤、關(guān)鍵代碼(b)和上述結(jié)構(gòu),大概可以猜到實(shí)例方法的調(diào)用順序:
1酸役、將一個(gè)objc_object結(jié)構(gòu)體的isa指針(即其對(duì)應(yīng)的objc_class結(jié)構(gòu)體)和一個(gè)方法名SEL傳入class_getMethodImplementation住诸。
2、在class_getMethodImplementation方法中涣澡,使用lookUpImpOrNil遍歷繼承鏈贱呐,若返回nil,則消息轉(zhuǎn)發(fā)(消息轉(zhuǎn)發(fā)下一章在講)暑塑。
3吼句、在lookUpImpOrNil遍歷繼承鏈锅必,即先在當(dāng)前objc_class的cache中查找SEL事格,若沒(méi)有,則在methodLists中查找搞隐,若存在驹愚,則將其放入該objc_class的cache中,然后返回IMP劣纲。若不存在逢捺,則通過(guò)super_class指針找到該class的父class,繼續(xù)該步驟直到NSObject停止(NSObject的super_class指向nil)癞季。
4劫瞳、執(zhí)行得到的IMP倘潜。

調(diào)用順序的第3步也解釋了objc_class 結(jié)構(gòu)體中cache的存在意義。

圖示

實(shí)例對(duì)象的isa和繼承鏈

3志于、結(jié)論與問(wèn)題

本節(jié)介紹了objc_msgSend工作原理涮因、objc_object的isa和objc_class的super_class等的使用方式,但是有一個(gè)和本章相關(guān)的成員沒(méi)有提到伺绽,即objc_class結(jié)構(gòu)體的isa指針养泡。無(wú)疑,它是和類方法的調(diào)用直接相關(guān)的奈应。

五澜掩、類方法調(diào)用和元類(metaClass)

上面留下的最后一個(gè)問(wèn)題,objc_class結(jié)構(gòu)體的isa指針問(wèn)題杖挣。無(wú)疑是和類方法調(diào)用直接相關(guān)的肩榕。

1、類方法調(diào)用與實(shí)例方法調(diào)用區(qū)別

類方法的調(diào)用和實(shí)例方法顯然不用惩妇,后者是需要先創(chuàng)建一個(gè)實(shí)例点把,而這個(gè)實(shí)例在堆中有自己對(duì)應(yīng)的objc_object結(jié)構(gòu)體,是以這個(gè)結(jié)構(gòu)體對(duì)應(yīng)的其“私有”的objc_class結(jié)構(gòu)體為基礎(chǔ)進(jìn)行消息傳遞的屿附。
那么郎逃,類方法呢?類方法不需要?jiǎng)?chuàng)建實(shí)例挺份,每個(gè)類都有一個(gè)自己對(duì)應(yīng)的現(xiàn)成的objc_class結(jié)構(gòu)體褒翰。而類方法的調(diào)用也是以這個(gè)“公有”的objc_class結(jié)構(gòu)體做操作的。

公有匀泊、私有指的是每個(gè)對(duì)象實(shí)例都有自己的objc_class(私有)优训,實(shí)例方法的調(diào)用也是通過(guò)這個(gè)私有的objc_class,而每個(gè)類只有一個(gè)對(duì)應(yīng)的objc_class(公有)各聘,任何地方調(diào)用類方法揣非,都是通過(guò)這個(gè)公有的objc_class。

2躲因、methodLists中的方法

代碼

// OC代碼
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface A : NSObject
@property (nonatomic, assign) NSInteger a;
- (void)b;
+ (void)d;
@end
@implementation A
- (void)b {
    NSLog(@"b");
}
+ (void)d {
    NSLog(@"d");
}
@end
int main(int argc, char * argv[]) {  
    // 在A對(duì)應(yīng)的objc_class結(jié)構(gòu)體的繼承鏈中找到實(shí)例方法b
    IMP bIMP = class_getMethodImplementation([A class], @selector(b));
    // 執(zhí)行IMP
    bIMP();
}

// 輸出
2016-12-29 18:21:39.810 block[74277:689120] b

分析
可知早敬,可以從A的objc_class的methodLists找到方法b。但是大脉,嘗試將

IMP bIMP = class_getMethodImplementation([A class], @selector(b));

改為

IMP bIMP = class_getMethodImplementation([A class], @selector(d));

執(zhí)行代碼搞监,會(huì)crash×螅可以得出結(jié)論琐驴,objc_class的methodLists中只存有實(shí)例方法,并沒(méi)有類方法。那么類方法在哪里绝淡?

類方法的位置

// OC代碼
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface A : NSObject
@property (nonatomic, assign) NSInteger a;
- (void)b;
+ (void)d;
@end
@implementation A
- (void)b {
    NSLog(@"b");
}
+ (void)d {
    NSLog(@"d");
}
@end
int main(int argc, char * argv[]) {
    // 獲取A類對(duì)應(yīng)的metaClass
    Class aMeta = objc_getMetaClass(class_getName([A class]));
    // 在metaClass中找類方法d
    IMP dIMP = class_getMethodImplementation(aMeta, @selector(d));
    dIMP();
}

// 輸出
2016-12-29 18:27:19.290 block[74821:695164] d

可知宙刘,A的objc_class結(jié)構(gòu)體有一個(gè)現(xiàn)成的metaClass,而它存有A類的類方法牢酵。這里大概可以想到A類的objc_class結(jié)構(gòu)體里面的isa指針指向這個(gè)metaClass荐类。

當(dāng)然,metaClass里面只存了類方法茁帽,沒(méi)有實(shí)例方法玉罐。

3、元類(metaClass)

由代碼

Class aMeta = objc_getMetaClass(class_getName([A class]));

可知潘拨,元類也是一個(gè)objc_class結(jié)構(gòu)體吊输。而相應(yīng)的也有isa和super_class成員。super_class比較好理解铁追,參照四中objc_msgSend實(shí)現(xiàn)饶唤,用于在繼承鏈上方法的查找咪啡。而元類的isa均指向NSObject對(duì)應(yīng)的元類,這里不多解釋(NSObject對(duì)應(yīng)元類的isa指向自己,其super_class指向NSObject逆瑞,也不解釋了)痹栖。

4才睹、類方法調(diào)用流程

// 類方法調(diào)用咆繁,參照一
objc_msgSend(objc_getClass("A"), sel_registerName("c"));

// 順便給出objc_class結(jié)構(gòu)
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

可知,objc_getClass("A")艾船,即為獲取A的class葵腹,結(jié)合四中objc_msgSend實(shí)現(xiàn),將其isa指針指向的metaClass傳入class_getMethodImplementation來(lái)進(jìn)行查找屿岂,符合我們的預(yù)期践宴。其后的步驟與實(shí)例方法相同。

5爷怀、類調(diào)用圖示

類的isa和繼承鏈

六阻肩、結(jié)論

結(jié)合四和五的圖展示,現(xiàn)在运授,你看懂這個(gè)圖了嗎烤惊。(可以發(fā)現(xiàn)本文在四中留下了兩個(gè)疑問(wèn),即動(dòng)態(tài)綁定和消息轉(zhuǎn)發(fā)徒坡,且等下一篇分享)


runtime經(jīng)典圖

七撕氧、文獻(xiàn)

1瘤缩、http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/
2喇完、http://blog.csdn.net/reylen/article/details/50440450
3、http://cocoasamurai.blogspot.jp/2010/01/understanding-objective-c-runtime.html
4、http://blog.ibireme.com/2013/11/26/objective-c-messaging/
5锦溪、https://github.com/opensource-apple/objc4

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末不脯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刻诊,更是在濱河造成了極大的恐慌防楷,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件则涯,死亡現(xiàn)場(chǎng)離奇詭異复局,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)粟判,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門亿昏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人档礁,你說(shuō)我怎么就攤上這事角钩。” “怎么了呻澜?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵递礼,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我羹幸,道長(zhǎng)脊髓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任栅受,我火速辦了婚禮供炼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窘疮。我一直安慰自己袋哼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布闸衫。 她就那樣靜靜地躺著涛贯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔚出。 梳的紋絲不亂的頭發(fā)上弟翘,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音骄酗,去河邊找鬼稀余。 笑死,一個(gè)胖子當(dāng)著我的面吹牛趋翻,可吹牛的內(nèi)容都是我干的睛琳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼师骗!你這毒婦竟也來(lái)了历等?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辟癌,失蹤者是張志新(化名)和其女友劉穎寒屯,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黍少,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寡夹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厂置。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片要出。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖农渊,靈堂內(nèi)的尸體忽然破棺而出患蹂,到底是詐尸還是另有隱情,我是刑警寧澤砸紊,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布传于,位于F島的核電站,受9級(jí)特大地震影響醉顽,放射性物質(zhì)發(fā)生泄漏沼溜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一游添、第九天 我趴在偏房一處隱蔽的房頂上張望系草。 院中可真熱鬧,春花似錦唆涝、人聲如沸找都。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)能耻。三九已至,卻和暖如春亡驰,著一層夾襖步出監(jiān)牢的瞬間晓猛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工凡辱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戒职,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓透乾,卻偏偏與公主長(zhǎng)得像洪燥,于是被迫代替她去往敵國(guó)和親磕秤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉蚓曼,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,721評(píng)論 0 9
  • 我們常常會(huì)聽(tīng)說(shuō) Objective-C 是一門動(dòng)態(tài)語(yǔ)言亲澡,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢钦扭?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,195評(píng)論 0 7
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 735評(píng)論 0 2
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 763評(píng)論 0 1
  • 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí)纫版,它使得 Objective-C 如虎添翼,具備了靈活的...
    lylaut閱讀 802評(píng)論 0 4