OC-KVC原理分析

OC之Method_Swizling一些坑點(diǎn)壁熄、KVC原理分析

Method_Swizling

Method_Swizling我們并不陌生,通過交換兩個(gè)方法SEL的IMP指向闻坚,達(dá)到方法交換的目的货岭。一般來說鲜漩,我們通常寫在cateogry里苍息,在+load()方法里實(shí)現(xiàn)方法的交換廓奕。

常規(guī)的方法交換

// SSJPerson.h
@interface SSJPerson : NSObject

  • (void)person_walk;
    @end

// SSJPerson.m

import "SSJPerson.h"

@implementation SSJPerson

  • (void)person_walk{
    NSLog(@"SSJPerson ---> person_walk");
    }

// SSJStudent.h
// SSJStudent 繼承自 SSJPerson
@interface SSJStudent : SSJPerson

  • (void)student_sleep;
    @end

// SSJStudent.m

import "SSJStudent.h"

@implementation SSJStudent

  • (void)student_sleep{
    NSLog(@"SSJStudent ---> student_sleep");
    }
    @end

//SSJStudent+category.m

import "SSJStudent+category.h"

import <objc/runtime.h>

@implementation SSJStudent (category)

  • (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    Method originalMethod = class_getInstanceMethod([self class], @selector(student_sleep));
    Method swizzlingMethod = class_getInstanceMethod([self class], @selector(student_sleepNew));
    method_exchangeImplementations(originalMethod, swizzlingMethod);
    });

}

  • (void)student_sleepNew{
    NSLog(@"替換過的方法 -- > student_sleepNew");
    [self student_sleepNew];
    }
    @end
    復(fù)制代碼
    調(diào)用的時(shí)候:

SSJStudent *stu = [SSJStudent new];
[stu student_sleep];
復(fù)制代碼
運(yùn)行也沒問題:

image.png

父類實(shí)現(xiàn),子類沒有實(shí)現(xiàn)

那么替換一個(gè)父類的已經(jīng)實(shí)現(xiàn)了档叔,但當(dāng)前cateogry類沒實(shí)現(xiàn)的方法呢?

對(duì)代碼進(jìn)行修改:

// SSJStudent+category.m

import "SSJStudent+category.h"

import <objc/runtime.h>

@implementation SSJStudent (category)

  • (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    /// 替換父類方法:person_walk
    /// 父類實(shí)現(xiàn)了person_walk蒸绩,子類并沒實(shí)現(xiàn)person_walk
    Method originalMethod = class_getInstanceMethod([self class], @selector(person_walk));
    Method swizzlingMethod = class_getInstanceMethod([self class], @selector(person_walkNew));
    method_exchangeImplementations(originalMethod, swizzlingMethod);
    });

}

//- (void)student_sleepNew{
// NSLog(@"替換過的方法 -- > student_sleepNew");
// [self student_sleepNew];
//}

  • (void)person_walkNew{
    NSLog(@"替換過的方法 -- > person_walkNew");
    [self person_walkNew];
    }

@end
復(fù)制代碼
// ViewController.m
@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];

    SSJStudent *student = [SSJStudent new];
    /// 這里換成person_walk
    [student person_walk];
    }

@end
復(fù)制代碼
運(yùn)行:

image.png

看打印結(jié)果衙四,子類調(diào)用person_walk都沒問題。

這里對(duì)ViewController.m添加兩行代碼:

// ViewController.m
@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];

    SSJStudent *student = [SSJStudent new];
    /// 這里換成person_walk
    [student person_walk];
    NSLog(@"\n");
    /// 添加代碼患亿,父類也調(diào)用person_walk
    SSJPerson *person = [SSJPerson new];
    [person person_walk];
    }

@end
復(fù)制代碼
再次運(yùn)行传蹈,就發(fā)現(xiàn)提示找不到方法:

image.png

這邊我畫了一張圖:

image.png

由于SSJStudent+category內(nèi)部實(shí)現(xiàn)了+load()方法,導(dǎo)致程序在load_images階段步藕,就調(diào)用了+load()方法惦界。

而+load()方法里對(duì)父類(SSJPerson)的person_walk方法進(jìn)行了替換,導(dǎo)致父類在調(diào)用自己方法person_walk的時(shí)候咙冗,提示找不到具體的person_walkNew實(shí)現(xiàn)沾歪,因?yàn)楦割惛揪蜎]這個(gè)方法。

在實(shí)際多人開發(fā)過程中雾消,提供父類的那個(gè)人他不一定知道你交換了父類的方法灾搏,當(dāng)他調(diào)用自己父類的方法時(shí),可能就一下子對(duì)這個(gè)報(bào)錯(cuò)感到莫名其妙:我明明沒有調(diào)用這個(gè)方法啊立润,為什么提示這個(gè)錯(cuò)誤狂窑?

如何避免這種子類替換了父類的方法,子類自己卻沒有實(shí)現(xiàn)父類方法的情況呢桑腮?
我們對(duì)SSJStudent+category.m的+load()方法進(jìn)行修改:

// SSJStudent+category.m

import "SSJStudent+category.h"

import <objc/runtime.h>

@implementation SSJStudent (category)

  • (void)load{
    /// 替換父類方法:person_walk
    /// 父類實(shí)現(xiàn)了person_walk泉哈,子類并沒實(shí)現(xiàn)person_walk
    Method originalMethod = class_getInstanceMethod([self class], @selector(person_walk));
    Method swizzlingMethod = class_getInstanceMethod([self class], @selector(person_walkNew));
    //添加一個(gè)Method(SEL - person_walk,IMP - person_walkNew)
    BOOL isAdded = class_addMethod([self class], method_getName(originalMethod), method_getImplementation(swizzlingMethod), method_getTypeEncoding(originalMethod));
    if(isAdded){
    /// 添加成功 ,就說明子類沒有實(shí)現(xiàn)父類person_walk對(duì)應(yīng)的IMP方法.
    /// 經(jīng)過class_addMethod這一步丛晦,子類已經(jīng)有了一個(gè)person_walk方法奕纫,并且IMP指向person_walkNew
    /// 接下來,直接添加一個(gè)Method(SEL - person_walkNew采呐,IMP - person_walk)
    /// 然后子類就實(shí)現(xiàn)了有了兩個(gè)IMP互相交換的Method,最終效果跟method_exchangeImplementations一樣
    class_replaceMethod([self class], method_getName(swizzlingMethod), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }else{
    ///添加不成功若锁,說明子類本身就已經(jīng)實(shí)現(xiàn)了person_walk的IMP方法,那就直接交換兩個(gè)Method的IMP即可
    method_exchangeImplementations(originalMethod, swizzlingMethod);
    }

}
復(fù)制代碼
運(yùn)行效果:

image.png

簡單來說斧吐,就是:

class_addMethod添加Method(SEL - person_walk又固,IMP - person_walkNew)

成功 -》則調(diào)用class_replaceMethod添加Method(SEL - person_walkNew,IMP - person_walk)煤率。

失敗 -》則調(diào)用method_exchangeImplementations交換兩個(gè)Method的IMP指向仰冠。

為了便于理解,我畫了張圖

image.png

說明:

class_addMethod:只能在SEL沒有IMP指向時(shí)才可以添加成功蝶糯;
class_replaceMethod:不管SEL 有沒有IMP實(shí)現(xiàn)洋只,都可以添加成功;
父類沒有實(shí)現(xiàn)昼捍,子類也沒有實(shí)現(xiàn)

把父類實(shí)現(xiàn)部分注釋

image.png

然后再運(yùn)行:

image.png

提示找不到這個(gè)person_walk這個(gè)方法實(shí)現(xiàn)识虚,那就說明category那里出了問題。
我們?cè)赾lass_getInstanceMethod那一行打上斷點(diǎn):

image.png

由于父類和子類都沒有實(shí)現(xiàn)person_walk妒茬,導(dǎo)致這邊獲取的originalMethod為空担锤。

我們對(duì)category的+load()方法進(jìn)行修改,添加originalMethod空值處理:

  • (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

      /// 替換父類方法:person_walk
      /// 父類實(shí)現(xiàn)了person_walk乍钻,子類并沒實(shí)現(xiàn)person_walk
      Method originalMethod = class_getInstanceMethod([self class], @selector(person_walk));
      Method swizzlingMethod = class_getInstanceMethod([self class], @selector(person_walkNew));
      if (!originalMethod) {
      /// 沒有肛循,那就添加一個(gè)person_walk方法,并且手動(dòng)添加一個(gè)臨時(shí)處理的IMP實(shí)現(xiàn)
         class_addMethod([self class], @selector(person_walk), method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
          /// originalMethod需要重新獲取一邊银择,不然依舊是空的
          originalMethod = class_getInstanceMethod([self class], @selector(person_walk));
          method_setImplementation(originalMethod, imp_implementationWithBlock(^(id self,SEL _cmd){
              NSLog(@"臨時(shí)方法");
          }));
      }
      //添加一個(gè)Method(SEL - person_walk多糠,IMP - person_walkNew)
      BOOL isAdded = class_addMethod([self class], method_getName(originalMethod), method_getImplementation(swizzlingMethod), method_getTypeEncoding(originalMethod));
      if(isAdded){
          /// 添加成功 ,就說明子類沒有實(shí)現(xiàn)父類person_walk對(duì)應(yīng)的IMP方法.
          /// 經(jīng)過class_addMethod這一步浩考,子類已經(jīng)有了一個(gè)person_walk方法夹孔,并且IMP指向person_walkNew
          /// 接下來,直接添加一個(gè)Method(SEL - person_walkNew析孽,IMP - person_walk)
          /// 然后子類就實(shí)現(xiàn)了有了兩個(gè)IMP互相交換的Method,最終效果跟method_exchangeImplementations一樣
          class_replaceMethod([self class], method_getName(swizzlingMethod), method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
      }else{
          ///添加不成功析蝴,說明子類本身就已經(jīng)實(shí)現(xiàn)了person_walk的IMP方法,那就直接交換兩個(gè)Method的IMP即可
          method_exchangeImplementations(originalMethod, swizzlingMethod);
      }
    

    });

}
復(fù)制代碼
運(yùn)行:

image.png

KVC分析

在講解KVC之前绿淋,請(qǐng)先允許我演示一段騷操作闷畸,對(duì)SSJPerson類的未開放屬性進(jìn)行讀寫操作:

// SSJPerson.h

import <Foundation/Foundation.h>

@interface SSJPerson : NSObject
@end

// SSJPerson.m

import "SSJPerson.h"

@interface SSJPerson ()
/// 昵稱
@property (nonatomic , strong) NSString *nickName_private;
@end
@implementation SSJPerson
@end
復(fù)制代碼
image.png

如圖所示,對(duì)于一個(gè)未開放出來的屬性吞滞,我們無法通過對(duì)象.屬性名這種常規(guī)的方式進(jìn)行訪問佑菩。但是我們可以利用setValue:forKey:這方式進(jìn)行賦值盾沫。

這種通過setValue:forKey:方式進(jìn)行賦值的操作,我們稱之為KVC殿漠。
KVC是一種設(shè)計(jì)模式赴精,那么它的原理又是什么呢?為什么可以對(duì)未開放屬性進(jìn)行直接操作呢绞幌?

存在即是真理蕾哟。帶著探索的思維,我們決定去看一下setValue:forKey:的底層實(shí)現(xiàn)莲蜘。

進(jìn)入蘋果官方文檔:KVC部分

image.png

大概意思是:
NSObject提供的NSKeyValueCoding協(xié)議谭确,默認(rèn)實(shí)現(xiàn)使用一組明確定義的規(guī)則,將基于密鑰的訪問器調(diào)用映射到對(duì)象的底層屬性票渠。這些協(xié)議方法使用一個(gè)關(guān)鍵參數(shù)來搜索它們自己的對(duì)象實(shí)例逐哈,以查找訪問器、實(shí)例變量和遵循某些命名約定的相關(guān)方法问顷。

Setter

接下來看一下Setter搜索模式: image.png

按照?qǐng)D上所說昂秃,Setter搜索模式分為3步:

找set<Key>: 或 _set<Key>,找到了就調(diào)用它杜窄;

如果沒找到肠骆,就去依次查找_<key>, is<Key>, <key>, 或is<Key>,找到了就用輸入值設(shè)置變量(比如找到了查找<key>,那么后面的_is<Key>等就不需要找了)。

如果還是沒找到塞耕,就會(huì)調(diào)用setValue:forUndefinedKey:并引發(fā)異常哗戈。

我們來根據(jù)這3個(gè)步驟,實(shí)操一下:

// SSJPerson.h
@interface SSJPerson : NSObject{
@public
NSString *boddy;
NSString *_boddy;
NSString *isBoddy;
NSString *_isBoddy;
}
@end

// SSJPerson.m
//(根據(jù)第2步荷科,找個(gè)要設(shè)置為YES)
@implementation SSJPerson

  • (BOOL)accessInstanceVariablesDirectly{
    return true;
    }
    @end

// ViewController.m

  • (void)viewDidLoad {
    [super viewDidLoad];
    /// 設(shè)置值
    [personA setValue:@"足球" forKey:@"boddy"];
    /// 打印內(nèi)容,我們要看一下具體賦值給哪個(gè)值
    NSLog(@"_<key>---%@",personA->_boddy);
    NSLog(@"_is<Key>---%@",personA ->_isBoddy);
    NSLog(@"<key>---%@",personA ->boddy);
    NSLog(@"is<Key>---%@",personA ->isBoddy);
    }
    復(fù)制代碼
    運(yùn)行:

image.png

注釋_boddy:

image.png

注釋_isBoddy:

image.png

這也就驗(yàn)證了里第2點(diǎn):當(dāng)存在多個(gè)類似變量纱注,會(huì)依次查找_<key>, _is<Key>, <key>, 或is<Key>畏浆,找到了就給它賦值,后面的就賦值了狞贱。
思考:關(guān)于第一點(diǎn)set<Key>:刻获,是不是也有第2點(diǎn)類似的關(guān)系呢?

image.png

注釋setBoddy方法:

image.png

注釋_setBoddy方法:

image.png

注釋setIsBoddy方法:

image.png

經(jīng)過4次打印瞎嬉,我們發(fā)現(xiàn)蝎毡,在我們調(diào)用setValue:forKey:的時(shí)候,會(huì)依次查找: set<Key>: > _set<Key> > setIs<Key>氧枣。找到后就用輸入值賦值給變量

Getter

接下來看一下Getter:

IMG_0978.JPG

大概意思如下:

1沐兵、查找 get<Key>, <key>, is<Key>, or _<key>,找到了就進(jìn)入步驟5便监;找不到就進(jìn)入步驟2扎谎;

2碳想、在實(shí)例方法中搜索:countOf<Key>和objectIn<Key>AtIndex和<key>AtIndexes:,
countOf<Key>必須實(shí)現(xiàn)毁靶,另外兩個(gè)找到了其中一個(gè)胧奔,就創(chuàng)建集合代理對(duì)象,找不到就進(jìn)入步驟3预吆;

3龙填、改為搜索countOf<Key>、Enumeratorf<Key>和memberOf<Key>:拐叉,3個(gè)方法都存在才行岩遗,否則就進(jìn)入步驟4;

4巷嚣、當(dāng)確定AccessInstanceVariables方法返回YES(默認(rèn)也是YES)喘先,
順序搜索名為 _<key>, _is<Key>, <key>, 或is<Key>的實(shí)例變量。
如果找到廷粒,直接獲取實(shí)例變量的值并繼續(xù)執(zhí)行步驟5窘拯。否則,繼續(xù)執(zhí)行步驟6坝茎。

5涤姊、如果檢索到的屬性值是對(duì)象指針,只需返回結(jié)果嗤放。
如果該值是NSNumber支持的標(biāo)量類型思喊,請(qǐng)將其存儲(chǔ)在NSNumber實(shí)例中并返回該值。
如果結(jié)果是NSNumber不支持的標(biāo)量類型次酌,請(qǐng)轉(zhuǎn)換為NSValue對(duì)象并返回該對(duì)象恨课。

6、如果都找不到岳服,調(diào)用valueForUndefinedKey:并拋出異常剂公。
復(fù)制代碼
針對(duì)第1點(diǎn),我們來進(jìn)行實(shí)操:

// SSJPerson.m

  • (NSString *)getBoddy{
    NSLog(@"%s -->Getter",func);
    return boddy;
    }

  • (NSString *)boddy{
    NSLog(@"%s -->Getter",func);
    return boddy;
    }

  • (NSString *)isBoddy{
    NSLog(@"%s -->Getter",func);
    return isBoddy;
    }

  • (NSString *)_boddy{
    NSLog(@"%s -->Getter",func);
    return _boddy;
    }

// ViewController.m

  • (void)viewDidLoad {
    [super viewDidLoad];
    SSJPerson *personA = [SSJPerson new];
    /// 設(shè)置值
    [personA setValue:@"足球" forKey:@"boddy"];
    NSLog(@"打印---%@",[personA valueForKey:@"boddy"]);
    }

復(fù)制代碼
運(yùn)行:

image.png

注釋getBoddy:

image.png

注釋boddy:

image.png

注釋isBoddy: image.png

至于為什么只有boddy方法執(zhí)行之后吊宋,valueForKey才打印出內(nèi)容纲辽,那是因?yàn)槟J(rèn)情況下,setter和getter是一一對(duì)應(yīng)的關(guān)系璃搜,setter模式優(yōu)先執(zhí)行<key>方法拖吼,getter模式對(duì)應(yīng)著_boddy方法。

針對(duì)第2點(diǎn)这吻,我們來進(jìn)行實(shí)操

在實(shí)例方法中搜索:countOf<Key>和objectIn<Key>AtIndex和<key>AtIndexes:吊档,
countOf<Key>必須實(shí)現(xiàn),另外兩個(gè)找到了其中一個(gè)唾糯,就創(chuàng)建集合代理對(duì)象籍铁,找不到就進(jìn)入步驟
復(fù)制代碼
這里不能使用boddyArray涡上,不然會(huì)走第一步的Getter方法:

image.png

把key改為myBoddyArray

image.png

注釋掉objectInMyBoddyArrayAtIndex:方法:

image.png

針對(duì)第3點(diǎn),我們來進(jìn)行實(shí)操

改為搜索countOf<Key>拒名、Enumeratorf<Key>和memberOf<Key>:吩愧,3個(gè)方法都存在才行,否則就進(jìn)入步驟4增显;
復(fù)制代碼
image.png

針對(duì)第4點(diǎn)雁佳,我們來進(jìn)行實(shí)操

當(dāng)確定AccessInstanceVariables方法返回YES(默認(rèn)也是YES),
順序搜索名為 _<key>, _is<Key>, <key>, 或is<Key>的實(shí)例變量同云。
如果找到糖权,直接獲取實(shí)例變量的值并繼續(xù)執(zhí)行步驟5。否則炸站,繼續(xù)執(zhí)行步驟6星澳。
復(fù)制代碼
image.png 注釋_boddy:

image.png

注釋_isBoddy:

image.png

注釋boddy:

image.png

針對(duì)第6點(diǎn),我們來進(jìn)行實(shí)操

如果都找不到旱易,調(diào)用valueForUndefinedKey:并拋出異常
復(fù)制代碼
在不做處理的情況下禁偎,用一個(gè)不存在的key去訪問,會(huì)報(bào)錯(cuò):

image.png

我們實(shí)現(xiàn)一下valueForUndefinedKey:阀坏,然后:

image.png

總結(jié)一下KVC的Setter和Getter

Setter:

依次查找set<Key>: 或 _set<Key>如暖,找到了就調(diào)用方法;找不到就進(jìn)入步驟2忌堂;

先確定AccessInstanceVariables返回YES盒至,然后依次查找_<key>, _is<Key>, <key>, 或is<Key>,找到了就用輸入值設(shè)置變量。找不到就進(jìn)入步驟3士修;

(比如找到了查找_<key>,那么后面的_is<Key>等就不需要找了)枷遂。

調(diào)用setValue:forUndefinedKey:并引發(fā)異常。
Getter:

查找 get<Key>, <key>, is<Key>, or _<key>棋嘲,找到了就進(jìn)入步驟5酒唉;找不到就進(jìn)入步驟2;

在實(shí)例中搜索:countOf<Key>和objectIn<Key>AtIndex和<key>AtIndexes:封字, 其中countOf<Key>必須實(shí)現(xiàn),另外兩個(gè)找到了其中一個(gè)耍鬓,就創(chuàng)建集合代理對(duì)象阔籽,找不到就進(jìn)入步驟3;

改為搜索countOf<Key>牲蜀、enumeratorf<Key>和memberOf<Key>:笆制,3個(gè)方法都存在才行,否則就進(jìn)入步驟4涣达;

當(dāng)確定AccessInstanceVariables方法返回YES(默認(rèn)也是YES)在辆, 順序搜索名為 _<key>, _is<Key>, <key>, 或is<Key>的實(shí)例變量证薇。 如果找到,直接獲取實(shí)例變量的值并繼續(xù)執(zhí)行步驟5匆篓。否則浑度,繼續(xù)執(zhí)行步驟6。

如果檢索到的屬性值是對(duì)象指針鸦概,只需返回結(jié)果箩张。 如果該值是NSNumber支持的標(biāo)量類型,請(qǐng)將其存儲(chǔ)在NSNumber實(shí)例中并返回該值窗市。 如果結(jié)果是NSNumber不支持的標(biāo)量類型先慷,請(qǐng)轉(zhuǎn)換為NSValue對(duì)象并返回該對(duì)象。

如果都找不到咨察,調(diào)用valueForUndefinedKey:并拋出異常论熙。

至此,我們就完成了KVC的探索摄狱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脓诡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子二蓝,更是在濱河造成了極大的恐慌誉券,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刊愚,死亡現(xiàn)場離奇詭異踊跟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鸥诽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門商玫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牡借,你說我怎么就攤上這事拳昌。” “怎么了钠龙?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵炬藤,是天一觀的道長。 經(jīng)常有香客問我碴里,道長沈矿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任咬腋,我火速辦了婚禮羹膳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘根竿。我一直安慰自己陵像,他們只是感情好就珠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著醒颖,像睡著了一般匠楚。 火紅的嫁衣襯著肌膚如雪揍拆。 梳的紋絲不亂的頭發(fā)上倦畅,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天乾闰,我揣著相機(jī)與錄音,去河邊找鬼疏日。 笑死偿洁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沟优。 我是一名探鬼主播涕滋,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼挠阁!你這毒婦竟也來了宾肺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤侵俗,失蹤者是張志新(化名)和其女友劉穎锨用,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體隘谣,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡增拥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寻歧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掌栅。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖码泛,靈堂內(nèi)的尸體忽然破棺而出猾封,到底是詐尸還是另有隱情,我是刑警寧澤噪珊,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布晌缘,位于F島的核電站,受9級(jí)特大地震影響痢站,放射性物質(zhì)發(fā)生泄漏磷箕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一瑟押、第九天 我趴在偏房一處隱蔽的房頂上張望搀捷。 院中可真熱鬧星掰,春花似錦多望、人聲如沸嫩舟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽家厌。三九已至,卻和暖如春椎工,著一層夾襖步出監(jiān)牢的瞬間饭于,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工维蒙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掰吕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓颅痊,卻偏偏與公主長得像殖熟,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斑响,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354