基于FMDB構建網絡緩存

核心思想:存儲的Key 經過MD5加密,將NSDictionary;NSArray;NSString;NSData轉換為NSString 存儲為text格式,同時將數據類型寫入數據表;讀取時,根據儲存的數據類型還原即可;

上代碼:

先來看一眼API:

/**
 *  更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param urlString    以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param parameter    parameter
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
 *  強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param urlString    以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param parameter    parameter
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)forceUpdataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;

/**
 *  更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param key          以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;

/**
 *  強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param key          以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)forceUpdataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;

/**
 *  加載緩存數據
 *
 *  @param urlString url
 *  @param parameter 參數
 *
 *  @return 緩存數據
 */
-(id)loadCacheWithUrl:(NSString *)urlString parameter:(id) parameter;

/**
 *  加載緩存數據
 *
 *  @param key 緩存數據庫的 key: 內部以KeyMD5作為Key
 *
 *  @return 緩存數據
 */
-(id)loadCacheWithKey:(NSString *)key;

/**
 *  清空緩存數據表
 */
-(void)clearDatabaseTable;

核心代碼片段:

NSDictionary;NSArray;NSString;NSData轉換為NSString,便于寫入數據表


- (NSString *)stringWithData:(id )data{
    if ([data isKindOfClass:[NSDictionary class]]) { // 數組/字典
        NSData      *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
        return  [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }else if ([data isKindOfClass:[NSArray class]]){
        NSArray *array = data;
        return [array componentsJoinedByString:@","];
    }else if([data isKindOfClass:[NSData class]]){
        return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }else if([data isKindOfClass:[NSString class]]){
        return data;
    }else{
        NSAssert(NO, @"數據類型不支持,目前只支持: NSDictionary;NSArray;NSString;NSData");
    }
    return nil;
}

數據讀取后還原過程

- (id)dataWithString:(NSString *)string classType:(NSNumber *)classType{

    NSInteger  type = [classType integerValue];
    switch (type) {
        case ClassTypeDictionary:{
            NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
            return  [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
        }break;
        case ClassTypeArray:
            return [string componentsSeparatedByString:@","];
            break;
        case ClassTypeData:
            return [string dataUsingEncoding:NSUTF8StringEncoding];
            break;
        case ClassTypeString:
            return string;
            break;
        default: // ClassTypeOther
            return nil;
            break;
    }
}

以下為FMDB 基本使用方法:

創(chuàng)建數據庫

-(void)creatScarchRecodeTable{
    
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains
                              (NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *path = [documentPath stringByAppendingPathComponent:@"DTDateCache.db"];
    _database = [FMDatabase databaseWithPath:path];
      NSLog(@"%@",path);
    if ([_database open]) {
        @try {
          [_database executeUpdate:[NSString stringWithFormat:@"create table if not exists DTCacheTable  (id integer PRIMARY KEY AUTOINCREMENT, keyName text, creatTime text, validTime text,cacheData text,classType integer)"]];
          
        } @catch (NSException *exception) {
            NSAssert(NO, exception.description);
        } @finally {
        }  
    }
}

插入數據

-(void)insertDataString:(NSString  *)data   withKey:(NSString *)key  classType:(NSNumber *)classtype{
    if (/* DISABLES CODE */ (NO)) {
        FMResultSet * result = [_database executeQuery:@"SELECT * FROM table order by time desc LIMIT 1"];
        [_database executeUpdate:[NSString stringWithFormat:@"DELETE FROM DTCacheTable WHERE name='%@'",[result stringForColumn:@"recode"]]];
    }
    [self creatScarchRecodeTable];
    NSString *sqlite = [NSString stringWithFormat:@"INSERT INTO DTCacheTable (keyName,creatTime,validTime,cacheData,classType) VALUES (?,?,?,?,?)"];
    NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
    NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];
    BOOL success = [_database executeUpdate:sqlite, key,creatTime,validTime,data,classtype];
    NSString *des = [NSString stringWithFormat:@"%@",[_database lastErrorMessage]];
//    [_database close];
    NSAssert(success, des);
}

更新數據

-(void)updataDataWithKey:(NSString *)key cacheData:(NSString *)cacheData classType:(NSNumber *)classtype{
    @try {
        [self creatScarchRecodeTable];
        NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
        NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];

        NSString *update = [NSString stringWithFormat:@"UPDATE DTCacheTable SET creatTime = ?, validTime = ?, cacheData = ?, classType = ?   WHERE keyName = ? "];
        [_database executeUpdate:update,creatTime,validTime,cacheData,classtype,key];
//        [_database close];
    } @catch (NSException *exception) {
        NSAssert(NO, exception.description);
    } @finally {

    }
}

查詢數據

-(NSDictionary *)selectDataFromTableWithKey:(NSString *)key{
    
    FMResultSet * result = [_database executeQuery:[NSString stringWithFormat:@"SELECT * FROM DTCacheTable"]];
    while ([result next]) {
        if ([key isEqualToString: [result stringForColumn:@"keyName"]]) {
            NSNumber *classType = [NSNumber numberWithInt:[result intForColumn:@"classType"]];
           NSString *content = [result stringForColumn:@"cacheData"];
          return [NSDictionary dictionaryWithObjectsAndKeys:classType,@"classType",content,@"content", nil];
        }
    }
//    [_database close];
    return nil;
}

以下是完整代碼:

#import <Foundation/Foundation.h>

@interface DTSqliteManager : NSObject

singleTon_h(DTSqliteManager)

/**
 *  更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param urlString    以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param parameter    parameter
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
 *  強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param urlString    以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param parameter    parameter
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)forceUpdataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;

/**
 *  更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param key          以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;

/**
 *  強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
 *
 *  @param key          以url的host,soureUrl,參數列表,拼接之后MD5作為Key
 *  @param cacheData    cacheData
 *  @param cacheSeconds 緩存有效期
 */
-(void)forceUpdataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;

/**
 *  加載緩存數據
 *
 *  @param urlString url
 *  @param parameter 參數
 *
 *  @return 緩存數據
 */
-(id)loadCacheWithUrl:(NSString *)urlString parameter:(id) parameter;

/**
 *  加載緩存數據
 *
 *  @param key 緩存數據庫的 key: 內部以KeyMD5作為Key
 *
 *  @return 緩存數據
 */
-(id)loadCacheWithKey:(NSString *)key;

/**
 *  清空緩存數據表
 */
-(void)clearDatabaseTable;
@end
#import "DTSqliteManager.h"
#import <FMDB/FMDB.h>
#import <sqlite3.h>
#import <CommonCrypto/CommonDigest.h>
//#import "sys/utsname.h"
typedef NS_ENUM(NSUInteger, ClassType) {
    ClassTypeDictionary = 1 << 0,
    ClassTypeArray      = 1 << 1,
    ClassTypeString     = 1 << 2,
    ClassTypeData       = 1 << 3,
    ClassTypeOther      = 1 << 4
};

@interface DTSqliteManager()
@end

@implementation DTSqliteManager{
    FMDatabase *_database;
    NSInteger   _cacheValidTime;
}

singleTon_m(DTSqliteManager)

#pragma mark - 創(chuàng)建數據庫和表
-(void)creatScarchRecodeTable{
    
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains
                              (NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *path = [documentPath stringByAppendingPathComponent:@"DTDateCache.db"];
    _database = [FMDatabase databaseWithPath:path];
      NSLog(@"%@",path);
    if ([_database open]) {
        @try {
          [_database executeUpdate:[NSString stringWithFormat:@"create table if not exists DTCacheTable  (id integer PRIMARY KEY AUTOINCREMENT, keyName text, creatTime text, validTime text,cacheData text,classType integer)"]];
          
        } @catch (NSException *exception) {
            NSAssert(NO, exception.description);
        } @finally {
        }
        
    }
}

#pragma mark - 緩存數據庫-插入數據
-(void)insertDataString:(NSString  *)data   withKey:(NSString *)key  classType:(NSNumber *)classtype{
    if (/* DISABLES CODE */ (NO)) {
        FMResultSet * result = [_database executeQuery:@"SELECT * FROM table order by time desc LIMIT 1"];
        [_database executeUpdate:[NSString stringWithFormat:@"DELETE FROM DTCacheTable WHERE name='%@'",[result stringForColumn:@"recode"]]];
    }
    [self creatScarchRecodeTable];
    NSString *sqlite = [NSString stringWithFormat:@"INSERT INTO DTCacheTable (keyName,creatTime,validTime,cacheData,classType) VALUES (?,?,?,?,?)"];
    NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
    NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];
    BOOL success = [_database executeUpdate:sqlite, key,creatTime,validTime,data,classtype];
    NSString *des = [NSString stringWithFormat:@"%@",[_database lastErrorMessage]];
//    [_database close];
    NSAssert(success, des);
}

-(void)updataDataWithKey:(NSString *)key cacheData:(NSString *)cacheData classType:(NSNumber *)classtype{
    @try {
        [self creatScarchRecodeTable];
        NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
        NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];

        NSString *update = [NSString stringWithFormat:@"UPDATE DTCacheTable SET creatTime = ?, validTime = ?, cacheData = ?, classType = ?   WHERE keyName = ? "];
        [_database executeUpdate:update,creatTime,validTime,cacheData,classtype,key];
//        [_database close];
    } @catch (NSException *exception) {
        NSAssert(NO, exception.description);
    } @finally {

    }
}

#pragma mark - 緩存數據庫-查詢數據
-(NSDictionary *)selectDataFromTableWithKey:(NSString *)key{
    
    FMResultSet * result = [_database executeQuery:[NSString stringWithFormat:@"SELECT * FROM DTCacheTable"]];
    while ([result next]) {
        if ([key isEqualToString: [result stringForColumn:@"keyName"]]) {
            NSNumber *classType = [NSNumber numberWithInt:[result intForColumn:@"classType"]];
           NSString *content = [result stringForColumn:@"cacheData"];
          return [NSDictionary dictionaryWithObjectsAndKeys:classType,@"classType",content,@"content", nil];
        }
    }
//    [_database close];
    return nil;
}

#pragma mark - 清空緩存數據庫
-(void)clearDatabaseTable{
    
    BOOL success = [_database executeUpdate:[NSString stringWithFormat:@"DELETE FROM DTCacheTable"]];
    NSString *des = [NSString stringWithFormat:@"%@",[_database lastErrorMessage]];
    NSAssert(success, des);
}

#pragma mark - 數據庫表名
//-(NSString *)getDatabaseTableName{
//    return [@"DTCache" dt_Md5Str];
//}



-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds forceUpdata:(BOOL)force{
    _cacheValidTime = cacheSeconds;
    NSString * key_MD5 =[self stringToMD5String:[NSString stringWithFormat:@"%@%@",urlString,parameter]] ;
    //根據緩存是否存在,執(zhí)行更新還是插入;
    if ([self hasCacheWiWithKey:key_MD5]) {
        if (force) {
            // 更新
             [self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
        }else{
            if ([self cacheTimeOutWithKey:key_MD5]) {
                [self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
            }
        }
    }else{
        // 插入
        [self insertDataString:[self stringWithData:cacheData] withKey:key_MD5 classType:[self classTypeWithData:cacheData]];
    }

}

-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
    [self updataCacheWithUrl:urlString parameter:parameter cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:NO];
}
-(void)forceUpdataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
    [self updataCacheWithUrl:urlString parameter:parameter cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:NO];
}


-(BOOL)hasCacheWiWithKey:(NSString *)key{
    return  [self selectDataFromTableWithKey:key] ? YES:NO;
}

-(BOOL)cacheTimeOutWithKey:(NSString *)key{
    FMResultSet * result = [_database executeQuery:[NSString stringWithFormat:@"SELECT * FROM DTCacheTable"]];
    while ([result next]) {
        if ([key isEqualToString:[result stringForColumn:@"keyName"]]) {
            NSLog(@"+++++%f",[[result stringForColumn:@"validTime"]  doubleValue]);
            NSLog(@"緩存有效期%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000));
            NSLog(@"當前時間:%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000));
            return  [[result stringForColumn:@"validTime"]  intValue] > (int)(kCFAbsoluteTimeIntervalSince1970 / 1000) ? NO:YES;
        }
    }
    return YES;
}



-(void)updataCacheWithKey:(NSString *)key cacheData:(id)cacheData cacheValidTime:(NSInteger)cacheSeconds forceUpdata:(BOOL)force{
    NSString*  key_MD5 = [self stringToMD5String:key];
    _cacheValidTime = cacheSeconds;
    //根據緩存是否存在,執(zhí)行更新還是插入;
    if ([self hasCacheWiWithKey:key_MD5]) {
        if (force) {
            // 更新
            [self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];

        }else{
            if ([self cacheTimeOutWithKey:key_MD5]) {
                // 更新
                [self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
            }
        }
    }else{
        // 插入
        [self insertDataString:[self stringWithData:cacheData] withKey:key_MD5 classType:[self classTypeWithData:cacheData]];
    }
}


-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
    [self updataCacheWithKey:key cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:NO];
}
-(void)forceUpdataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
    [self updataCacheWithKey:key cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:YES];
}

-(id)loadCacheWithUrl:(NSString *)urlString parameter:(id) parameter;{
    NSString *key_MD5 = [self stringToMD5String:[NSString stringWithFormat:@"%@%@",urlString,parameter]];
    if ([self hasCacheWiWithKey:key_MD5]) {
        NSDictionary *diction = [self selectDataFromTableWithKey:key_MD5];
        return [self  dataWithString:[diction objectForKey:@"content"] classType:[diction objectForKey:@"classType"]];
    }
    return nil;
}

-(id)loadCacheWithKey:(NSString *)key{
    NSString *key_MD5 = [self stringToMD5String:key];
    if ([self hasCacheWiWithKey:key_MD5]) {
        NSDictionary *diction = [self selectDataFromTableWithKey:key_MD5];
        return [self  dataWithString:[diction objectForKey:@"content"] classType:[diction objectForKey:@"classType"]];
    }
    return nil;
}

-(NSString *)stringToMD5String:(NSString *)string;{
    const char *cStr = [string UTF8String];
    unsigned char result[16];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
    return [NSString stringWithFormat:
            @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
            result[0], result[1], result[2], result[3],
            result[4], result[5], result[6], result[7],
            result[8], result[9], result[10], result[11],
            result[12], result[13], result[14], result[15]
            ];
}

- (id)dataWithString:(NSString *)string classType:(NSNumber *)classType{

    NSInteger  type = [classType integerValue];
    switch (type) {
        case ClassTypeDictionary:{
            NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
            return  [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
        }break;
        case ClassTypeArray:
            return [string componentsSeparatedByString:@","];
            break;
        case ClassTypeData:
            return [string dataUsingEncoding:NSUTF8StringEncoding];
            break;
        case ClassTypeString:
            return string;
            break;
        default: // ClassTypeOther
            return nil;
            break;
    }
}

- (NSString *)stringWithData:(id )data{
    if ([data isKindOfClass:[NSDictionary class]]) { // 數組/字典
        NSData      *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
        return  [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }else if ([data isKindOfClass:[NSArray class]]){
        NSArray *array = data;
        return [array componentsJoinedByString:@","];
    }else if([data isKindOfClass:[NSData class]]){
        return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }else if([data isKindOfClass:[NSString class]]){
        return data;
    }else{
        NSAssert(NO, @"數據類型不支持,目前只支持: NSDictionary;NSArray;NSString;NSData");
    }
    return nil;
}

-(NSNumber *)classTypeWithData:(id)data{
    if ([data isKindOfClass:[NSArray class]]) {
        return [NSNumber numberWithInteger:ClassTypeArray];
    }else if ([data isKindOfClass:[NSDictionary class]]){
        return [NSNumber numberWithInteger:ClassTypeDictionary];
    }else if ([data isKindOfClass:[NSString class]]){
        return [NSNumber numberWithInteger:ClassTypeString];
    }else if ([data isKindOfClass:[NSData class]]){
        return [NSNumber numberWithInteger:ClassTypeData];
    }else{
        return [NSNumber numberWithInteger:ClassTypeOther];
    }
}
@end

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末智蝠,一起剝皮案震驚了整個濱河市铸抑,隨后出現的幾起案子,更是在濱河造成了極大的恐慌歼培,老刑警劉巖毅往,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異漾稀,居然都是意外死亡,警方通過查閱死者的電腦和手機建瘫,發(fā)現死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門崭捍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人啰脚,你說我怎么就攤上這事殷蛇。” “怎么了橄浓?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵粒梦,是天一觀的道長。 經常有香客問我荸实,道長匀们,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任准给,我火速辦了婚禮泄朴,結果婚禮上,老公的妹妹穿的比我還像新娘露氮。我一直安慰自己祖灰,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布畔规。 她就那樣靜靜地躺著局扶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叁扫。 梳的紋絲不亂的頭發(fā)上三妈,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音陌兑,去河邊找鬼沈跨。 笑死由捎,一個胖子當著我的面吹牛兔综,可吹牛的內容都是我干的。 我是一名探鬼主播狞玛,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼软驰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了心肪?” 一聲冷哼從身側響起锭亏,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎硬鞍,沒想到半個月后慧瘤,有當地人在樹林里發(fā)現了一具尸體戴已,經...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年锅减,在試婚紗的時候發(fā)現自己被綠了糖儡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡怔匣,死狀恐怖握联,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情每瞒,我是刑警寧澤金闽,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站剿骨,受9級特大地震影響代芜,放射性物質發(fā)生泄漏。R本人自食惡果不足惜懦砂,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一蜒犯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荞膘,春花似錦罚随、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至屠升,卻和暖如春潮改,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腹暖。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工汇在, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人脏答。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓糕殉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親殖告。 傳聞我的和親對象是個殘疾皇子阿蝶,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內容