iOS runtime實(shí)用篇--和常見(jiàn)崩潰say good-bye!

say no.jpg

源碼

https://github.com/chenfanfang/AvoidCrash


程序崩潰經(jīng)歷

其實(shí)在很早之前就想寫(xiě)這篇文章了,一直拖到現(xiàn)在。

  • 程序崩潰經(jīng)歷1
  • 我們公司做的是股票軟件,但集成的是第三方的靜態(tài)庫(kù)(我們公司和第三方公司合作,他們提供股票的服務(wù),我們付錢(qián))。平時(shí)開(kāi)發(fā)測(cè)試的時(shí)候好好的,結(jié)果上線(xiàn)幾天發(fā)現(xiàn)有崩潰的問(wèn)題,其實(shí)責(zé)任大部分在我身上。
    • 我的責(zé)任: 過(guò)分信賴(lài)文檔,沒(méi)進(jìn)行容錯(cuò)處理,也就是沒(méi)有對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的判斷處理。
    • 下面附上代碼,說(shuō)明崩潰的原因

因第三方公司提供的數(shù)據(jù)錯(cuò)亂導(dǎo)致有時(shí)候創(chuàng)建字典的時(shí)候個(gè)別value為nil才導(dǎo)致的崩潰

//宏
#define CStringToOcString(cstr) [NSString stringWithCString:cstr encoding:GBK_ENCODE]


//將每組數(shù)據(jù)都保存起來(lái)
NSMutableArray *returnArray = [NSMutableArray array];
for (int i = 0; i < recordM.count; i++) {
   Withdrawqry_entrust_record *record = (Withdrawqry_entrust_record *)alloca(sizeof(Withdrawqry_entrust_record));
   memset(record, 0x00, sizeof(Withdrawqry_entrust_record));
   [[recordM objectAtIndex:i] getValue:record];
   

   //崩潰的原因在創(chuàng)建字典的時(shí)候,有個(gè)別value為nil  (CStringToOcString)

   NSDictionary *param =   @{           
     @"batch_no" : CStringToOcString(record->batch_no),// 委托批號(hào)
     @"entrust_no" : CStringToOcString(record->entrust_no),// 委托編號(hào)
     @"entrust_type" : @(record->entrust_type),//委托類(lèi)別  6 融資委托 7 融券委托 和entrust_bs結(jié)合形成融資買(mǎi)入,融資賣(mài)出,融券賣(mài)出,融券買(mǎi)入
     @"entrust_bs" : @(record->entrust_bs),// 買(mǎi)賣(mài)標(biāo)志
     @"stock_account" : CStringToOcString(record->stock_account),//證券賬號(hào)
     @"gdcode" : CStringToOcString(record->gdcode),
     .....
     .....
     .....
                           };
  • 解決辦法,在宏那里做了個(gè)判斷,若果value為nil,直接賦值為@""
#define CStringToOcString(cstr) [NSString stringWithCString:cstr encoding:GBK_ENCODE] ?
 [NSString stringWithCString:cstr encoding:GBK_ENCODE] : @""

  • 程序崩潰經(jīng)歷2
    不做過(guò)多的闡述,直接看代碼
    //服務(wù)器返回的日期格式為20160301
    //我要將格式轉(zhuǎn)換成2016-03-01

    /** 委托日期 */
    NSMutableString *dateStrM = 服務(wù)器返回的數(shù)據(jù)

    [dateStrM insertString:@"-" atIndex:4];
    [dateStrM insertString:@"-" atIndex:7];

就是上面的代碼導(dǎo)致了上線(xiàn)的程序崩潰,搞的我在第二天緊急再上線(xiàn)了一個(gè)版本。
為何會(huì)崩潰呢?原因是服務(wù)器返回的數(shù)據(jù)錯(cuò)亂了,返回了0。這樣字符串的長(zhǎng)度就為1,而卻插入下標(biāo)為4的位置,程序必然會(huì)崩潰。后來(lái)在原本代碼上加了一個(gè)判斷,如下代碼:

  if (dateStrM.length >= 8) {
      [dateStrM insertString:@"-" atIndex:4];
      [dateStrM insertString:@"-" atIndex:7];
   }

醒悟

  • 1、不要過(guò)分相信服務(wù)器返回的數(shù)據(jù)會(huì)永遠(yuǎn)的正確。
  • 2、在對(duì)數(shù)據(jù)處理上,要進(jìn)行容錯(cuò)處理,進(jìn)行相應(yīng)判斷之后再處理數(shù)據(jù),這是一個(gè)良好的編程習(xí)慣。

思考:如何防止存在潛在崩潰方法的崩潰

  • 眾所周知,F(xiàn)oundation框架里有非常多常用的方法有導(dǎo)致崩潰的潛在危險(xiǎn)。對(duì)于一個(gè)已經(jīng)將近竣工的項(xiàng)目,若起初沒(méi)做容錯(cuò)處理又該怎么辦?你總不會(huì)一行行代碼去排查有沒(méi)有做容錯(cuò)處理吧!-------- 別逗逼了,老板催你明天就要上線(xiàn)了!
  • 那有沒(méi)有一種一勞永逸的方法?無(wú)需動(dòng)原本的代碼就可以解決潛在崩潰的問(wèn)題呢?

解決方案

攔截存在潛在崩潰危險(xiǎn)的方法,在攔截的方法里進(jìn)行相應(yīng)的處理,就可以防止方法的崩潰

步驟:


具體實(shí)現(xiàn)

創(chuàng)建一個(gè)工具類(lèi)AvoidCrash,來(lái)處理方法的交換,獲取會(huì)導(dǎo)致崩潰代碼的具體位置,在控制臺(tái)輸出錯(cuò)誤的信息......

AvoidCrash.h

//
//  AvoidCrash.h
//  AvoidCrash
//
//  Created by mac on 16/9/21.
//  Copyright ? 2016年 chenfanfang. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

//通知的名稱(chēng),若要獲取詳細(xì)的崩潰信息,請(qǐng)監(jiān)聽(tīng)此通知
#define AvoidCrashNotification @"AvoidCrashNotification"
#define AvoidCrashDefaultReturnNil  @"This framework default is to return nil."
#define AvoidCrashDefaultIgnore     @"This framework default is to ignore this operation to avoid crash."

@interface AvoidCrash : NSObject

/**
 *  become effective . You can call becomeEffective method in AppDelegate didFinishLaunchingWithOptions
 *  
 *  開(kāi)始生效.你可以在AppDelegate的didFinishLaunchingWithOptions方法中調(diào)用becomeEffective方法
 */
+ (void)becomeEffective;

+ (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel;

+ (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel;

+ (NSString *)getMainCallStackSymbolMessageWithCallStackSymbolStr:(NSString *)callStackSymbolStr;

+ (void)noteErrorWithException:(NSException *)exception defaultToDo:(NSString *)defaultToDo;

@end

AvoidCrash.m

//
//  AvoidCrash.m
//  AvoidCrash
//
//  Created by mac on 16/9/21.
//  Copyright ? 2016年 chenfanfang. All rights reserved.
//

#import "AvoidCrash.h"

//category
#import "NSArray+AvoidCrash.h"
#import "NSMutableArray+AvoidCrash.h"

#import "NSDictionary+AvoidCrash.h"
#import "NSMutableDictionary+AvoidCrash.h"

#import "NSString+AvoidCrash.h"
#import "NSMutableString+AvoidCrash.h"

#define AvoidCrashSeparator         @"================================================================"
#define AvoidCrashSeparatorWithFlag @"========================AvoidCrash Log=========================="

#define key_errorName        @"errorName"
#define key_errorReason      @"errorReason"
#define key_errorPlace       @"errorPlace"
#define key_defaultToDo      @"defaultToDo"
#define key_callStackSymbols @"callStackSymbols"
#define key_exception        @"exception"

@implementation AvoidCrash

/**
 *  開(kāi)始生效(進(jìn)行方法的交換)
 */
+ (void)becomeEffective {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        [NSArray avoidCrashExchangeMethod];
        [NSMutableArray avoidCrashExchangeMethod];
        
        [NSDictionary avoidCrashExchangeMethod];
        [NSMutableDictionary avoidCrashExchangeMethod];
        
        [NSString avoidCrashExchangeMethod];
        [NSMutableString avoidCrashExchangeMethod];
        
    });
}

/**
 *  類(lèi)方法的交換
 *
 *  @param anClass    哪個(gè)類(lèi)
 *  @param method1Sel 方法1
 *  @param method2Sel 方法2
 */
+ (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel {
    Method method1 = class_getClassMethod(anClass, method1Sel);
    Method method2 = class_getClassMethod(anClass, method2Sel);
    method_exchangeImplementations(method1, method2);
}

/**
 *  對(duì)象方法的交換
 *
 *  @param anClass    哪個(gè)類(lèi)
 *  @param method1Sel 方法1
 *  @param method2Sel 方法2
 */
+ (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel {
    Method method1 = class_getInstanceMethod(anClass, method1Sel);
    Method method2 = class_getInstanceMethod(anClass, method2Sel);
    method_exchangeImplementations(method1, method2);
}

/**
 *  獲取堆棧主要崩潰精簡(jiǎn)化的信息<根據(jù)正則表達(dá)式匹配出來(lái)>
 *
 *  @param callStackSymbolStr 堆棧主要崩潰信息
 *
 *  @return 堆棧主要崩潰精簡(jiǎn)化的信息
 */

+ (NSString *)getMainCallStackSymbolMessageWithCallStackSymbolStr:(NSString *)callStackSymbolStr {
    //不熟悉正則表達(dá)式的朋友,可以看我另外一篇文章,鏈接在下面
    //http://www.lxweimin.com/p/b25b05ef170d
      
    //mainCallStackSymbolMsg的格式為   +[類(lèi)名 方法名]  或者 -[類(lèi)名 方法名]
    __block NSString *mainCallStackSymbolMsg = nil;
    
    //匹配出來(lái)的格式為 +[類(lèi)名 方法名]  或者 -[類(lèi)名 方法名]
    NSString *regularExpStr = @"[-\\+]\\[.+\\]";
    
    NSRegularExpression *regularExp = [[NSRegularExpression alloc] initWithPattern:regularExpStr options:NSRegularExpressionCaseInsensitive error:nil];
    
    [regularExp enumerateMatchesInString:callStackSymbolStr options:NSMatchingReportProgress range:NSMakeRange(0, callStackSymbolStr.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
        if (result) {
            mainCallStackSymbolMsg = [callStackSymbolStr substringWithRange:result.range];
            *stop = YES;
        }
    }];
    
    
    
    return mainCallStackSymbolMsg;
}

/**
 *  提示崩潰的信息(控制臺(tái)輸出、通知)
 *
 *  @param exception   捕獲到的異常
 *  @param defaultToDo 這個(gè)框架里默認(rèn)的做法
 */
+ (void)noteErrorWithException:(NSException *)exception defaultToDo:(NSString *)defaultToDo {

    //堆棧數(shù)據(jù)
    NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
    
    //獲取在哪個(gè)類(lèi)的哪個(gè)方法中實(shí)例化的數(shù)組  字符串格式 -[類(lèi)名 方法名]  或者 +[類(lèi)名 方法名]
    NSString *mainCallStackSymbolMsg = [AvoidCrash getMainCallStackSymbolMessageWithCallStackSymbolStr:callStackSymbolsArr[2]];
    
    if (mainCallStackSymbolMsg == nil) {
        
        mainCallStackSymbolMsg = @"崩潰方法定位失敗,請(qǐng)您查看函數(shù)調(diào)用棧來(lái)排查錯(cuò)誤原因";
        
    }
    
    NSString *errorName = exception.name;
    NSString *errorReason = exception.reason;
    //errorReason 可能為 -[__NSCFConstantString avoidCrashCharacterAtIndex:]: Range or index out of bounds
    //將avoidCrash去掉
    errorReason = [errorReason stringByReplacingOccurrencesOfString:@"avoidCrash" withString:@""];
    
    NSString *errorPlace = [NSString stringWithFormat:@"Error Place:%@",mainCallStackSymbolMsg];
    
    NSString *logErrorMessage = [NSString stringWithFormat:@"\n\n%@\n\n%@\n%@\n%@\n%@\n\n%@\n\n",AvoidCrashSeparatorWithFlag, errorName, errorReason, errorPlace, defaultToDo, AvoidCrashSeparator];
    NSLog(@"%@", logErrorMessage);
    
    NSDictionary *errorInfoDic = @{
                                   key_errorName        : errorName,
                                   key_errorReason      : errorReason,
                                   key_errorPlace       : errorPlace,
                                   key_defaultToDo      : defaultToDo,
                                   key_exception        : exception,
                                   key_callStackSymbols : callStackSymbolsArr
                                   };
    
    //將錯(cuò)誤信息放在字典里,用通知的形式發(fā)送出去
    [[NSNotificationCenter defaultCenter] postNotificationName:AvoidCrashNotification object:nil userInfo:errorInfoDic];
}

@end

創(chuàng)建一個(gè)NSDictionary的分類(lèi),來(lái)防止創(chuàng)建一個(gè)字典而導(dǎo)致的崩潰。
NSDictionary+AvoidCrash.h

//
//  NSDictionary+AvoidCrash.h
//  AvoidCrash
//
//  Created by mac on 16/9/21.
//  Copyright ? 2016年 chenfanfang. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSDictionary (AvoidCrash)

+ (void)avoidCrashExchangeMethod;

@end

NSDictionary+AvoidCrash.m
在這里先補(bǔ)充一個(gè)知識(shí)點(diǎn): 我們平常用的快速創(chuàng)建字典的方式@{key : value}; 其實(shí)調(diào)用的方法是dictionaryWithObjects:forKeys:count: 而該方法可能導(dǎo)致崩潰的原因?yàn)? key數(shù)組中的key或者objects中的value為空

//
//  NSDictionary+AvoidCrash.m
//  AvoidCrash
//
//  Created by mac on 16/9/21.
//  Copyright ? 2016年 chenfanfang. All rights reserved.
//

#import "NSDictionary+AvoidCrash.h"

#import "AvoidCrash.h"

@implementation NSDictionary (AvoidCrash)

+ (void)avoidCrashExchangeMethod {
    
    [AvoidCrash exchangeClassMethod:self method1Sel:@selector(dictionaryWithObjects:forKeys:count:) method2Sel:@selector(avoidCrashDictionaryWithObjects:forKeys:count:)];
}

+ (instancetype)avoidCrashDictionaryWithObjects:(const id  _Nonnull __unsafe_unretained *)objects forKeys:(const id<NSCopying>  _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt {
    
    id instance = nil;
    
    @try {
        instance = [self avoidCrashDictionaryWithObjects:objects forKeys:keys count:cnt];
    }
    @catch (NSException *exception) {
        
        NSString *defaultToDo = @"This framework default is to remove nil key-values and instance a dictionary.";
        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
        
        //處理錯(cuò)誤的數(shù)據(jù),然后重新初始化一個(gè)字典
        NSUInteger index = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        id  _Nonnull __unsafe_unretained newkeys[cnt];
        
        for (int i = 0; i < cnt; i++) {
            if (objects[i] && keys[i]) {
                newObjects[index] = objects[i];
                newkeys[index] = keys[i];
                index++;
            }
        }
        instance = [self avoidCrashDictionaryWithObjects:newObjects forKeys:newkeys count:index];
    }
    @finally {
        return instance;
    }
}

@end

來(lái)看下防止崩潰的效果

  • 正常情況下,若沒(méi)有我們上面的處理,如下代碼就會(huì)導(dǎo)致崩潰
    NSString *nilStr = nil;
    NSDictionary *dict = @{
                           @"key" : nilStr
                           };

崩潰截圖如下:

崩潰截圖.png

  • 若通過(guò)如上的處理,就可以避免崩潰了
[AvoidCrash becomeEffective];

控制臺(tái)的輸出截圖如下

防止崩潰控制臺(tái)輸出的信息.png
  • 若想要獲取到崩潰的詳細(xì)信息(我們可以監(jiān)聽(tīng)通知,通知名為:AvoidCrashNotification):可以將這些信息傳到我們的服務(wù)器,或者在集成第三方收集Crash信息的SDK中自定義信息,這樣我們就可以防止程序的崩潰,并且又得知哪些代碼導(dǎo)致了崩潰。

 //監(jiān)聽(tīng)通知:AvoidCrashNotification, 獲取AvoidCrash捕獲的崩潰日志的詳細(xì)信息
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];




- (void)dealwithCrashMessage:(NSNotification *)note {
    
    //注意:所有的信息都在userInfo中
    //你可以在這里收集相應(yīng)的崩潰信息進(jìn)行相應(yīng)的處理(比如傳到自己服務(wù)器)
    NSLog(@"\n\n在AppDelegate中 方法:dealwithCrashMessage打印\n\n\n\n\n%@\n\n\n\n",note.userInfo);
}

附上一張截圖查看通知中攜帶的崩潰信息是如何的

AvoidCrashNotification通知的監(jiān)聽(tīng).png

結(jié)束語(yǔ)

  • 程序崩潰有崩潰的好處,就是讓開(kāi)發(fā)者快速認(rèn)識(shí)到自己所寫(xiě)的代碼有問(wèn)題,這樣才能及時(shí)修復(fù)BUG,當(dāng)然這種好處只限于在開(kāi)發(fā)階段。若一個(gè)上線(xiàn)APP出現(xiàn)崩潰的問(wèn)題,這問(wèn)題可就大了(老板不高興,后果很?chē)?yán)重)。

  • 個(gè)人建議:在發(fā)布的時(shí)候APP的時(shí)候再用上面介紹的方法來(lái)防止程序的崩潰,在開(kāi)發(fā)階段最好不用。

  • 上面只是舉個(gè)例子,更多防止崩潰的方法請(qǐng)查看Github源碼 AvoidCrash,這是我最近寫(xiě)的一個(gè)框架,大家可以集成到自己的項(xiàng)目中去,在發(fā)布APP的時(shí)候在appDelegate的didFinishLaunchingWithOptions中調(diào)用方法[AvoidCrash becomeEffective];即可,若要獲取崩潰信息,監(jiān)聽(tīng)通知即可。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [AvoidCrash becomeEffective];
    
    //監(jiān)聽(tīng)通知:AvoidCrashNotification, 獲取AvoidCrash捕獲的崩潰日志的詳細(xì)信息
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];
    return YES;
}

- (void)dealwithCrashMessage:(NSNotification *)note {
    
    //注意:所有的信息都在userInfo中
    //你可以在這里收集相應(yīng)的崩潰信息進(jìn)行相應(yīng)的處理(比如傳到自己服務(wù)器)
    NSLog(@"\n\n在AppDelegate中 方法:dealwithCrashMessage打印\n\n\n\n\n%@\n\n\n\n",note.userInfo);
}
  • 同時(shí)希望大家能夠提出更多容易導(dǎo)致崩潰的方法,我好添加到AvoidCrash框架中,當(dāng)然也歡迎大家和我一起維護(hù)這個(gè)框架。
  • 最后,希望大家給上你們珍貴的一票(帥哥、美女,給個(gè)star哈)。





AvoidCrash更新

2016-10-15

  • 修復(fù)上一個(gè)版本部分方法不能攔截崩潰的BUG,具體修復(fù)哪些可以查看issues和簡(jiǎn)書(shū)上的留言。
  • 優(yōu)化崩潰代碼的定位,定位崩潰代碼更加準(zhǔn)確。
  • 增加對(duì)KVC賦值防止崩潰的處理。
  • 增加對(duì)NSAttributedString防止崩潰的處理
  • 增加對(duì)NSMutableAttributedString防止崩潰的處理

2016-11-29

  • 修復(fù)在鍵盤(pán)彈出狀態(tài)下,按Home鍵進(jìn)入后臺(tái)會(huì)導(dǎo)致崩潰的bug。
  • 新增防止崩潰(NSArray、NSMutableArray) - (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes

2016-12-1

  • 處理數(shù)組的類(lèi)簇問(wèn)題,提高兼容性,不論是由于array[100]方式,還是[array objectAtIndex:100]方式 獲取數(shù)組中的某個(gè)元素操作不當(dāng)而導(dǎo)致的crash,都能被攔截防止崩潰。

  • 上一個(gè)版本只能防止array[100]導(dǎo)致的崩潰,不能防止[array objectAtIndex:100]導(dǎo)致的崩潰。

  • 統(tǒng)一對(duì)線(xiàn)程進(jìn)行處理,監(jiān)聽(tīng)通知AvoidCrashNotification后,不論是在主線(xiàn)程導(dǎo)致的crash還是在子線(xiàn)程導(dǎo)致的crash,監(jiān)聽(tīng)通知的方法統(tǒng)一在"主線(xiàn)程"中。

  • 上一個(gè)版本中,在哪個(gè)線(xiàn)程導(dǎo)致的crash, 則監(jiān)聽(tīng)通知的方法就在哪個(gè)線(xiàn)程中。

  • 新增防止崩潰 (NSArray、NSMutableArray) - (void)getObjects:(__unsafe_unretained id _Nonnull *)objects range:(NSRange)range










最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,610評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,939評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,004評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,173評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,247評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,580評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評(píng)論 2 380

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