Objective-C基礎(chǔ)-Runtime

1图仓、什么是Runtime

  • Objective-C是一門(mén)動(dòng)態(tài)性比較強(qiáng)的編程語(yǔ)言,跟C跳芳、C++等語(yǔ)言有著很大的不同
  • Objective-C的動(dòng)態(tài)性是由Runtime API來(lái)支撐的
  • Runtime API提供的接口基本都是C語(yǔ)言的洲脂,源碼由C\C++\匯編語(yǔ)言編寫(xiě)

2、isa詳解

  • 在arm64架構(gòu)之前励饵,isa就是一個(gè)普通的指針驳癌,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址
  • 從arm64架構(gòu)開(kāi)始役听,對(duì)isa進(jìn)行了優(yōu)化颓鲜,變成了一個(gè)共用體(union)結(jié)構(gòu),還使用位域來(lái)存儲(chǔ)更多的信息
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
    
    struct {
        uintptr_t nonpointer        : 1;
        uintptr_t has_assoc         : 1;
        uintptr_t has_cxx_dtor      : 1;
        uintptr_t shiftcls          : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
        uintptr_t magic             : 6;
        uintptr_t weakly_referenced : 1;
        uintptr_t deallocating      : 1;
        uintptr_t has_sidetable_rc  : 1;
        uintptr_t extra_rc          : 19;

    };
};
  • nonpointer 0代表普通的指針典予,存儲(chǔ)著Class甜滨、Meta-Class對(duì)象的內(nèi)存地址; 1代表優(yōu)化過(guò),使用位域存儲(chǔ)更多的信息瘤袖。
  • has_assoc 是否有設(shè)置過(guò)關(guān)聯(lián)對(duì)象衣摩,如果沒(méi)有,釋放時(shí)會(huì)更快捂敌。
  • has_cxx_dtor 是否有C++的析構(gòu)函數(shù)(.cxx_destruct)艾扮,如果沒(méi)有,釋放時(shí)會(huì)更快占婉。
  • shiftcls 存儲(chǔ)著Class泡嘴、Meta-Class對(duì)象的內(nèi)存地址信息。
  • magic 用于在調(diào)試時(shí)分辨對(duì)象是否未完成初始化逆济。
  • weakly_referenced 是否有被弱引用指向過(guò)酌予,如果沒(méi)有,釋放時(shí)會(huì)更快奖慌。
  • deallocating 對(duì)象是否正在釋放霎终。
  • has_sidetable_rc 引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中。如果為1升薯,那么引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫SideTable的類(lèi)的屬性中
  • extra_rc 里面存儲(chǔ)的值是引用計(jì)數(shù)器減1莱褒。

3、Class的結(jié)構(gòu)

struct objc_class {
    Class isa;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable涎劈, 方法緩存
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags广凸, 用于獲取具體的類(lèi)信息
    
    class_rw_t *data() { 
        return bits.data();
    }
};

class_rw_t

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro;           //編譯期的只讀信息

    method_array_t methods;     //方法列表
    property_array_t properties;    //屬性列表
    protocol_array_t protocols; //協(xié)議列表

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;
};
  • class_rw_t里面的methods阅茶、properties、protocols是二維數(shù)組谅海,是可讀可寫(xiě)的脸哀,包含了類(lèi)的初始內(nèi)容、分類(lèi)的內(nèi)容扭吁。
class_rw_t的method_array_t.jpg

class_ro_t

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize; //instance對(duì)象占用的內(nèi)存空間
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;      //類(lèi)名
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;  //成員變量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
};
  • class_ro_t里面的baseMethodList撞蜂、baseProtocols、ivars侥袜、baseProperties是一維數(shù)組蝌诡,是只讀的,包含了類(lèi)的初始內(nèi)容枫吧。
class_ro_t的method_list_t.jpg

method_t

  • method_t是對(duì)方法\函數(shù)的封裝
struct method_t {
    SEL name;               //函數(shù)名
    const char *types;  //編碼 (返回類(lèi)型浦旱、參數(shù)類(lèi)型)
    IMP imp;                //指向函數(shù)的指針(函數(shù)地址)
};
  • IMP代表函數(shù)的具體實(shí)現(xiàn)
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
  • SEL代表方法\函數(shù)名,一般叫做選擇器九杂,底層結(jié)構(gòu)跟char *類(lèi)似
    • 可以通過(guò)@selector()sel_registerName()獲得
    • 可以通過(guò)sel_getName()NSStringFromSelector()轉(zhuǎn)成字符串
    • 不同類(lèi)中相同名字的方法颁湖,所對(duì)應(yīng)的方法選擇器是相同的
typedef struct objc_selector *SEL;
  • types包含了函數(shù)返回值、參數(shù)編碼的字符串
返回值 參數(shù)1 參數(shù)2 ...... 參數(shù)n
  • Type Encoding
    iOS中提供了一個(gè)叫做@encode的指令例隆,可以將具體的類(lèi)型表示成字符串編碼

方法緩存

  • Class內(nèi)部結(jié)構(gòu)中有個(gè)方法緩存cache_t甥捺,用散列表(哈希表)來(lái)緩存曾經(jīng)調(diào)用過(guò)的方法,可以提高方法的查找速度镀层。
struct cache_t {
    struct bucket_t *_buckets;  //散列表
    mask_t _mask;                   //散列表的長(zhǎng)度減1
    mask_t _occupied;               //已經(jīng)緩存的方法數(shù)量
};

struct bucket_t {
private:
    cache_key_t _key;   //SEL作為Key
    IMP _imp;               //函數(shù)的內(nèi)存地址
};
  • 緩存查找
//objc-cache.mm
bucket_t * cache_t::find(cache_key_t k, id receiver)

4镰禾、objc_msgSend執(zhí)行流程

  • OC中的方法調(diào)用,其實(shí)都是轉(zhuǎn)換為objc_msgSend函數(shù)的調(diào)用
  • objc_msgSend的執(zhí)行流程可以分為3大階段
  • 消息發(fā)送
  • 動(dòng)態(tài)方法解析
  • 消息轉(zhuǎn)發(fā)
  • objc_msgSend源碼執(zhí)行流程
//objc-msg-arm64.s
ENTRY _objc_msgSend
b.le    LNilOrTagged
CacheLookup NORMAL
.macro CacheLookup
.macro CheckMiss
STATIC_ENTRY __objc_msgSend_uncached
.macro MethodTableLookup
__class_lookupMethodAndLoadCache3

STATIC_ENTRY __objc_msgForward_impcache
ENTRY __objc_msgForward


//objc-runtime-new.mm
_class_lookupMethodAndLoadCache3
lookUpImpOrForward
getMethodNoSuper_nolock鹿响、search_method_list羡微、log_and_fill_cache
cache_getImp谷饿、log_and_fill_cache惶我、getMethodNoSuper_nolock、log_and_fill_cache
_class_resolveInstanceMethod
_objc_msgForward_impcache

//Core Foundation
__forwarding__(不開(kāi)源)

4.1 objc_msgSend 消息發(fā)送流程

objc_msgSend執(zhí)行流程01-消息發(fā)送.jpg
  • 如果是從class_rw_t中查找方法
    已經(jīng)排序的博投,二分查找
    沒(méi)有排序的绸贡,遍歷查找
  • receiver通過(guò)isa指針找到receiverClass
  • receiverClass通過(guò)superclass指針找到superClass

4.2 objc_msgSend 動(dòng)態(tài)方法解析

objc_msgSend執(zhí)行流程02-動(dòng)態(tài)方法解析.jpg
  • 可以實(shí)現(xiàn)以下方法,來(lái)動(dòng)態(tài)添加方法實(shí)現(xiàn)
+resolveInstanceMethod:
+resolveInstanceMethod:
  • 動(dòng)態(tài)解析過(guò)后毅哗,會(huì)重新走“消息發(fā)送”的流程
    從receiverClass的cache中查找方法這一步開(kāi)始執(zhí)行

動(dòng)態(tài)添加類(lèi)方法

@interface Person : NSObject
+ (void)test;
@end

@implementation Person

+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(test)) {
        Class metaClass = object_getClass(self);//元類(lèi)
        Method method = class_getClassMethod(metaClass, @selector(other));
        // 動(dòng)態(tài)添加test方法的實(shí)現(xiàn)
        class_addMethod(metaClass, sel,
                        method_getImplementation(method),
                        method_getTypeEncoding(method));
        // 返回YES代表有動(dòng)態(tài)添加方法
        return YES;
    }
    return [super resolveClassMethod:sel];
}

+ (void)other {
    NSLog(@"%s", __func__);
}
@end

動(dòng)態(tài)添加實(shí)例方法

@interface Person : NSObject
- (void)test;
@end

@implementation Person

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(test)) {
        Class class = self;//Class類(lèi)
        Method method = class_getInstanceMethod(class, @selector(other));
        // 動(dòng)態(tài)添加test方法的實(shí)現(xiàn)
        class_addMethod(class, sel,
                        method_getImplementation(method),
                        method_getTypeEncoding(method));
        // 返回YES代表有動(dòng)態(tài)添加方法
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

- (void)other {
    NSLog(@"%s", __func__);
}

@end

4.3 objc_msgSend 消息轉(zhuǎn)發(fā)

objc_msgSend的執(zhí)行流程03-消息轉(zhuǎn)發(fā).jpg
  • 可以在forwardInvocation:方法中自定義任何邏輯
  • 以上方法都有對(duì)象方法听怕、類(lèi)方法2個(gè)版本(前面可以是加號(hào)+,也可以是減號(hào)-)

forwardingTargetForSelector

實(shí)例方法

@interface Cat : NSObject
- (void)test;
@end

@implementation Cat
- (void)test {
    NSLog(@"%s", __func__);
}
@end
@interface Person : NSObject
- (void)test;
@end

@implementation Person
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [[Cat alloc] init];
    }
    return [super forwardingTargetForSelector:aSelector];
}
@end

類(lèi)方法

@interface Cat : NSObject
+ (void)test;
@end

@implementation Cat
+ (void)test {
    NSLog(@"%s", __func__);
}
@end
@interface Person : NSObject
+ (void)test;
@end

@implementation Person
+ (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [Cat class];
    }
    return [super forwardingTargetForSelector:aSelector];
}
@end

forwardInvocation

實(shí)例方法

@interface Cat : NSObject
- (void)test;
@end

@implementation Cat
- (void)test {
    NSLog(@"%s", __func__);
}
@end

@interface Dog : NSObject
- (void)test;
@end

@implementation Dog
- (void)test {
    NSLog(@"%s", __func__);
}
@end
@interface Person : NSObject
- (void)test;
@end

@implementation Person

// 方法簽名:返回值類(lèi)型虑绵、參數(shù)類(lèi)型
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
    }
    return [super methodSignatureForSelector:aSelector];
}

/*
 NSInvocation封裝了一個(gè)方法調(diào)用尿瞭,包括:方法調(diào)用者、方法名翅睛、方法參數(shù)
 anInvocation.target 方法調(diào)用者
 anInvocation.selector 方法名
 [anInvocation getArgument:NULL atIndex:0]
 */
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    [anInvocation invokeWithTarget:[[Cat alloc] init]];
    [anInvocation invokeWithTarget:[[Dog alloc] init]];
}
@end

類(lèi)方法

@interface Cat : NSObject
+ (void)test;
@end

@implementation Cat
+ (void)test {
    NSLog(@"%s", __func__);
}
@end

@interface Dog : NSObject
+ (void)test;
@end

@implementation Dog
+ (void)test {
    NSLog(@"%s", __func__);
}
@end
@interface Person : NSObject
+ (void)test;
@end

@implementation Person

// 方法簽名:返回值類(lèi)型声搁、參數(shù)類(lèi)型
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(test)) {
        return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
    }
    return [super methodSignatureForSelector:aSelector];
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    [anInvocation invokeWithTarget:[Cat class]];
    [anInvocation invokeWithTarget:[Dog class]];
}
@end

4.4 降低doesNotRecognizeSelector崩潰

@interface Person : NSObject
- (void)run;
- (void)test;
- (void)other;
@end
@implementation Person

- (void)run {
    NSLog(@"run-123");
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    // 本來(lái)能調(diào)用的方法
    if ([self respondsToSelector:aSelector]) {
        return [super methodSignatureForSelector:aSelector];
    }
    
    // 找不到的方法
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

// 找不到的方法黑竞,都會(huì)來(lái)到這里
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *person = [[Person alloc] init];
        [person run];
        [person test];
        [person other];
    }
    return 0;
}
找不到方法輸出.jpg

寫(xiě)一個(gè)NSObject的分類(lèi)解決找不到方法問(wèn)題


@implementation NSObject (ForwardInvocation)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = self;
        Method method1 = class_getInstanceMethod(cls, @selector(methodSignatureForSelector:));
        Method method2 = class_getInstanceMethod(cls, @selector(fi_methodSignatureForSelector:));
        method_exchangeImplementations(method1, method2);
        
        Method method3 = class_getClassMethod(cls, @selector(methodSignatureForSelector:));
        Method method4 = class_getClassMethod(cls, @selector(fi_methodSignatureForSelector:));
        method_exchangeImplementations(method3, method4);
    });
}

- (NSMethodSignature *)fi_methodSignatureForSelector:(SEL)aSelector {
    if ([self respondsToSelector:aSelector]) {
        return [self fi_methodSignatureForSelector:aSelector];
    }
    
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

+ (NSMethodSignature *)fi_methodSignatureForSelector:(SEL)aSelector {
    if ([self respondsToSelector:aSelector]) {
        return [self fi_methodSignatureForSelector:aSelector];
    }
    
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}

+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}

@end

5、super的本質(zhì)

  • super調(diào)用疏旨,底層會(huì)轉(zhuǎn)換為objc_msgSendSuper2函數(shù)的調(diào)用很魂,接收2個(gè)參數(shù)
    • struct objc_super2
    • SEL
struct objc_super2 {
    id receiver;
    Class current_class;
};
  • receiver是消息接收者
  • current_classreceiverClass對(duì)象
@interface Person : NSObject
@end

@implementation Person
@end

@interface Student : Person
@end

@implementation Student

- (instancetype)init {
    if (self = [super init]) {
        NSLog(@"[self class] = %@", [self class]);
        NSLog(@"[self superclass] = %@", [self superclass]);
        NSLog(@"[super class] = %@", [super class]);
        NSLog(@"[super superclass] = %@", [super superclass]);
    }
    return self;
}

@end
superClass輸出.jpg

看objc源碼

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

struct objc_super {
    __unsafe_unretained _Nonnull id receiver; // 消息接收者
    __unsafe_unretained _Nonnull Class super_class; // 消息接收者的父類(lèi)
};
  • [super message]的底層實(shí)現(xiàn)
    1. 消息接收者仍然是子類(lèi)對(duì)象
    2. 從父類(lèi)開(kāi)始查找方法的實(shí)現(xiàn)
//[super run]轉(zhuǎn)化的源碼
struct __rw_objc_super { 
    struct objc_object *object; 
    struct objc_object *superClass;
};

static void _I_Student_run(Student * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));
}

簡(jiǎn)化下相當(dāng)于

struct __rw_objc_super arg = {self, [Person class]};
objc_msgSendSuper(arg, @selector(run));

[super class]輸出Student的原因
[super superclass]輸出Person的原因,

  • [super class]中的class方法只在NSObject才有檐涝。
  • 調(diào)用的是object_getClass(self); ,
  • self實(shí)際上是Student對(duì)象遏匆,對(duì)應(yīng)Student類(lèi)
  • 同理[super superclass]---> [self class]->superclass, 對(duì)應(yīng)Person類(lèi)

6、isKindOfClass谁榜、isMemberOfClass方法

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 這句代碼的方法調(diào)用者不管是哪個(gè)類(lèi)(只要是NSObject體系下的)幅聘,都返回YES
        NSLog(@"%d", [NSObject isKindOfClass:[NSObject class]]);   // 1
        NSLog(@"%d", [NSObject isMemberOfClass:[NSObject class]]); // 0
        NSLog(@"%d", [Person isKindOfClass:[Person class]]);       // 0
        NSLog(@"%d", [Person isMemberOfClass:[Person class]]);     // 0
    }
    return 0;
}

+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
isa-superclass.png

7、Runtime應(yīng)用

  • 利用關(guān)聯(lián)對(duì)象(AssociatedObject)給分類(lèi)添加屬性
  • 遍歷類(lèi)的所有成員變量(修改textfield的占位文字顏色惰爬、字典轉(zhuǎn)模型喊暖、自動(dòng)歸檔解檔)
  • 利用消息轉(zhuǎn)發(fā)機(jī)制解決方法找不到的異常問(wèn)題
  • 交換方法實(shí)現(xiàn)(交換系統(tǒng)的方法)Method Swizzling

8、練習(xí)

@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (void)print;
@end

@implementation Person
- (void)print {
    NSLog(@"name = %@", self.name);
}
@end
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    id cls = [Person class];
    void *obj = &cls;
    [(__bridge id)obj print];
}
@end

調(diào)用輸出


練習(xí)輸出.jpg

1撕瞧、為什么print能打印成功

  • obj存儲(chǔ)的是cla的地址陵叽,cls存儲(chǔ)的地址是[Person class]的地址。
  • 與實(shí)例對(duì)象調(diào)用類(lèi)似丛版,person存儲(chǔ)的是isa的地址巩掺,通過(guò)isa找到[Person class],調(diào)用print方法。所以能調(diào)用成功
Person *person = [[Person alloc] init];
[person print];
cls指向問(wèn)題.jpg

2页畦、輸出為什么變?yōu)?code>ViewController或者其他的

[super viewDidLoad];

轉(zhuǎn)化為C++函數(shù)胖替,其實(shí)有個(gè)臨時(shí)的self變量

struct abc = {
    self,
    [ViewController class]
};
objc_msgSendSuper2(abc, sel_registerName("viewDidLoad"));

viewDidLoad方法各個(gè)臨時(shí)變量在函數(shù)中的內(nèi)存地址是在棧中的,棧的地址是從高到低的豫缨,地址分布如下:

棧地址.jpg

cls相當(dāng)于isa, 其下面一個(gè)地址就是_name的地址独令,所以會(huì)輸出ViewController

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末好芭,一起剝皮案震驚了整個(gè)濱河市燃箭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舍败,老刑警劉巖招狸,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異邻薯,居然都是意外死亡裙戏,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)厕诡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)累榜,“玉大人,你說(shuō)我怎么就攤上這事灵嫌∫挤#” “怎么了冀偶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)渔嚷。 經(jīng)常有香客問(wèn)我进鸠,道長(zhǎng),這世上最難降的妖魔是什么形病? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任客年,我火速辦了婚禮,結(jié)果婚禮上漠吻,老公的妹妹穿的比我還像新娘量瓜。我一直安慰自己,他們只是感情好途乃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布绍傲。 她就那樣靜靜地躺著,像睡著了一般耍共。 火紅的嫁衣襯著肌膚如雪烫饼。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天试读,我揣著相機(jī)與錄音杠纵,去河邊找鬼。 笑死钩骇,一個(gè)胖子當(dāng)著我的面吹牛比藻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播倘屹,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼银亲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了纽匙?” 一聲冷哼從身側(cè)響起务蝠,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哄辣,沒(méi)想到半個(gè)月后请梢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體赠尾,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡力穗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了气嫁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片当窗。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寸宵,靈堂內(nèi)的尸體忽然破棺而出崖面,到底是詐尸還是另有隱情元咙,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布巫员,位于F島的核電站庶香,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏简识。R本人自食惡果不足惜赶掖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望七扰。 院中可真熱鬧奢赂,春花似錦、人聲如沸颈走。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)立由。三九已至轧钓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锐膜,已是汗流浹背聋迎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枣耀,地道東北人霉晕。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像捞奕,于是被迫代替她去往敵國(guó)和親牺堰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

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

  • 我們常常會(huì)聽(tīng)說(shuō) Objective-C 是一門(mén)動(dòng)態(tài)語(yǔ)言颅围,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢伟葫?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,186評(píng)論 0 7
  • 文中的實(shí)驗(yàn)代碼我放在了這個(gè)項(xiàng)目中。 以下內(nèi)容是我通過(guò)整理[這篇博客] (http://yulingtianxia....
    茗涙閱讀 914評(píng)論 0 6
  • 本文轉(zhuǎn)自:楊蕭玉博客 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí)院促,它使得 Objective-C ...
    oneofai閱讀 204評(píng)論 0 0
  • 本文詳細(xì)整理了 Cocoa 的 Runtime 系統(tǒng)的知識(shí)筏养,它使得 Objective-C 如虎添翼,具備了靈活的...
    lylaut閱讀 795評(píng)論 0 4
  • 這幾天正好趕上月末和季度初常拓,特別特別忙渐溶,閨女被爺爺奶奶接走了,我已經(jīng)五天沒(méi)有見(jiàn)到她了弄抬,每天忙完工作就特別想她茎辐,今天...
    函寶媽咪閱讀 132評(píng)論 0 0