淺談iOS數(shù)據(jù)持久化

導(dǎo)語

數(shù)據(jù)持久化是一種非易失性存儲(chǔ)技術(shù)空免,在重啟動(dòng)計(jì)算機(jī)或設(shè)備后也不會(huì)丟失數(shù)據(jù)顽染,是將內(nèi)存中的數(shù)據(jù)模型轉(zhuǎn)換為存儲(chǔ)模型草丧,以及將存儲(chǔ)模型轉(zhuǎn)換為內(nèi)存中的數(shù)據(jù)模型的統(tǒng)稱狸臣。數(shù)據(jù)模型可以是任何數(shù)據(jù)結(jié)構(gòu)或?qū)ο竽P?存儲(chǔ)模型可以是關(guān)系模型、XML昌执、二進(jìn)制流等烛亦。持久化技術(shù)主要用于MVC模型中的model層。目前iOS平臺(tái)上主要使用如下的四種技術(shù):

一.NSUserDefaults(關(guān)鍵詞:屬性列表懂拾、xml序列化)

什么是NSUserDefaults煤禽?

在介紹NSUserDefaults之前,我們有必要先了解屬性列表的概念:屬性列表是一種基于xml序列化的數(shù)據(jù)永久存儲(chǔ)文件岖赋,又稱plist文件凛篙,原理是將一些基本數(shù)據(jù)類型讀寫進(jìn)plist文件(注:plist文件是xml格式文件,因?yàn)槌S糜诖鎯?chǔ)配置信息踱蠢,所以又稱作plist格式文件)并以明文方式存儲(chǔ)于設(shè)備中撮抓。許多OC的基本數(shù)據(jù)類型(如NSArray、NSString等)本身提供了向plist文件讀寫的方法栗涂,但實(shí)際項(xiàng)目中我們用的更多的是NSUserDefaults知牌,NSUserDefaults是蘋果基于屬性列表所封裝的一個(gè)單例類,該類提供了基本數(shù)據(jù)類型的plist文件存儲(chǔ)方法斤程,因其使用方便角寸,代碼易懂,NSUserDefaults成為了最常用的數(shù)據(jù)持久化方式之一忿墅。

NSUserDefaults常用方法
//從 NSUserDefaults 中取出 key 值所對(duì)應(yīng)的 Value
id = [[NSUserDefaults standardUserDefaults] objectForKey:(NSString *)];

//將數(shù)據(jù)對(duì)象存儲(chǔ)到 NSUserDefaults 中
[[NSUserDefaults standardUserDefaults] setObject:(id)
                                         forKey:(NSString *)];

//將數(shù)據(jù)對(duì)象從 NSUserDefaults 中移除
[[NSUserDefaults standardUserDefaults] removeObjectForKey(NSString *)];

//同步更新到Plist文件扁藕,當(dāng)修改了 NSUserDefaults 的數(shù)據(jù)后,必須進(jìn)行此步操作
[[NSUserDefaults standardUserDefaults] synchronize];
NSUserDefaults特點(diǎn)
  • NSUserDefaults常用于存儲(chǔ)OC基本數(shù)據(jù)類型疚脐,不適合存儲(chǔ)自定義對(duì)象亿柑,NSUserDefaults支持的數(shù)據(jù)類型有:NSNumber(NSInteger、float棍弄、double)望薄,NSString疟游,NSDate,NSArray痕支,NSDictionary颁虐,BOOL.
  • 自定義對(duì)象可以轉(zhuǎn)化成基本類型NSData后再使用NSUserDefaults進(jìn)行存儲(chǔ),但并不常用卧须。
  • 當(dāng)plist文件存儲(chǔ)的數(shù)據(jù)發(fā)生改變(寫操作)時(shí)另绩,需要調(diào)用synchronize方法同步,否則數(shù)據(jù)無法同步保存花嘶。
  • Key值應(yīng)具有唯一性笋籽,重名時(shí)將覆蓋先前的key值。
  • 實(shí)際開發(fā)中椭员,NSUserDefaults常用于存儲(chǔ)配置信息干签,優(yōu)點(diǎn)是簡(jiǎn)便,缺點(diǎn)是所有數(shù)據(jù)都以明文存儲(chǔ)在plist文件中拆撼,容易被解讀導(dǎo)致安全性不高容劳。

二.對(duì)象歸檔(關(guān)鍵詞:序列化)

什么是對(duì)象歸檔?

和屬性列表一樣闸度,對(duì)象歸檔也是將對(duì)象寫入文件并保存在硬盤內(nèi)竭贩,所以本質(zhì)上是另一種形式的序列化(儲(chǔ)存模型不同)。雖說任何對(duì)象都可以被序列化莺禁,但只有某些特定的對(duì)象才能放置到某個(gè)集合類(例如:NSArray留量、NSMutableArray、NSDictionary哟冬、NSData等)中楼熄,并使用該集合類的方法在屬性列表存儲(chǔ)中讀寫,一旦將包含了自定義對(duì)象的數(shù)組寫入屬性列表浩峡,程序就會(huì)報(bào)錯(cuò)可岂。歸檔與屬性列表方式不同,屬性列表只有指定的一些對(duì)象才能進(jìn)行持久化且明文存儲(chǔ)翰灾,而歸檔是任何實(shí)現(xiàn)了NSCopying協(xié)議的對(duì)象都可以被持久化缕粹,且歸檔后的文件是加密的。對(duì)象歸檔涉及兩個(gè)類:NSKeyedArchiver和NSKeyedUnarchiver纸淮,這兩個(gè)類是NSCoder的子類平斩,分別用于歸檔以及解檔。下面將介紹如何對(duì)自定義對(duì)象進(jìn)行歸檔咽块。

對(duì)象歸檔示例

現(xiàn)在绘面,我們有一個(gè)自定義的Person類,該類有name,age揭璃,height三個(gè)屬性晚凿,其.h文件如下

//Person.h
#import<Foundation/foundation.h>
@interface Person:NSObject<NSCoding>
@property(nonatomic,copy)NSString *name;
@property(nonatomic,assign)int age;
@property(nonatomic,assign)double height;

在.m文件中,我們要實(shí)現(xiàn)NSCoding中的兩個(gè)協(xié)議方法塘辅,這兩個(gè)方法分別在歸檔和解檔時(shí)會(huì)被調(diào)用,Person類的.m文件如下

//Person.m
#import"Person.h"
@implementation Person
/*
* 歸檔時(shí)調(diào)用該方法皆撩,該方法說明哪些數(shù)據(jù)需要儲(chǔ)存扣墩,怎樣儲(chǔ)存
*/
- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:_name forKey:@"name"];
    [encoder encodeInt:_age forKey:@"age"];
    [encoder encodeDouble:_name forKey:@"height"];
}

/*
* 歸檔時(shí)調(diào)用該方法,該方法說明哪些數(shù)據(jù)需要解析扛吞,怎樣解析
*/
-(id)initWithCoder:(NSCoder *)decode
{
    if (self = [super init]) {
        _name = [decode decodeObjectForKey:@"name"];
        _age = [decode decodeIntForKey:@"age"];
        _height = [decode decodeDoubleForKey:@"height"];
    }
    return self;
}
@end

這個(gè)Person類就具有了歸檔與解檔能力呻惕,當(dāng)你需要對(duì)一個(gè)Person類的實(shí)力對(duì)象進(jìn)行儲(chǔ)存或者解析時(shí),在你自己的方法中只要鍵入如下代碼即可滥比,下面兩個(gè)方法對(duì)應(yīng)兩個(gè)按鈕的回調(diào)亚脆,點(diǎn)擊按鈕時(shí)分別執(zhí)行person對(duì)象的歸檔和解檔。

//寫操作
- (IBAction)Write {
    Person *p = [[Person alloc]init];
    p.name = @"jin";
    p.age = 10;
    p.height = 176.0;

    //設(shè)置歸檔后文件路徑
    NSString *path = @"/Users/macbookair/Desktop/person.data";
    //歸檔
    [NSKeyedArchiver archiveRootObject:p toFile:path];
}

//讀操作
- (IBAction)read {
    
    //設(shè)置路徑
    NSString *path = @"/Users/macbookair/Desktop/person.data";
    
    //解檔
    Person *p = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    NSLog(@"%@--%d---%f",p.name ,p.age ,p.height);
    
}
對(duì)象歸檔特點(diǎn)
  • 可以將自定義對(duì)象寫入文件或從文件中讀出盲泛。
  • 由于歸檔時(shí)進(jìn)行了加密處理濒持,因此安全性高于屬性列表。

三.CoreData(關(guān)鍵詞:集成化)

什么是CoreData寺滚?

當(dāng)你的應(yīng)用程序需要在本地存儲(chǔ)大量的關(guān)系型數(shù)據(jù)模型時(shí)柑营,顯然上述方法并不適合,因?yàn)椴徽搶?duì)象歸檔還是數(shù)據(jù)列表村视,一旦數(shù)據(jù)模型之間存在依賴關(guān)系官套,問題就將變得復(fù)雜。而此時(shí)iPhone自帶的輕量級(jí)數(shù)據(jù)庫Sqlite便成為我們的首選蚁孔,如果你熟悉數(shù)據(jù)庫奶赔,那么恭喜,CoreData也將不再神秘杠氢,你可以理解為它是蘋果對(duì)Sqlite封裝的一個(gè)框架站刑,你可以在Xcode中進(jìn)行Sqlite數(shù)據(jù)庫的可視化操作。倘若你對(duì)Sqlite感到陌生鼻百,那么本文最后也將對(duì)Sqlite進(jìn)行簡(jiǎn)單的講解笛钝。

如何使用CoreData?

1.新建自帶CoreData文件的工程項(xiàng)目,當(dāng)你創(chuàng)建成功后愕宋,左邊文件列表里將看到xxx.xcdatamodeld玻靡。并且在AppDelegate類中會(huì)自動(dòng)生成一系列相關(guān)屬性和方法用于管理CoreData。當(dāng)然你也可以為已有項(xiàng)目添加CoreData文件中贝,不過AppDelegate類則需要你重新構(gòu)造相關(guān)方法囤捻。

1.新建帶CoreData的工程項(xiàng)目

2.點(diǎn)擊xxx.xcdatamodeld文件,你會(huì)看到一個(gè)CoreData文件相當(dāng)于一個(gè)數(shù)據(jù)庫邻寿,在這里你可以進(jìn)行建表蝎土、添加屬性视哑、連接表與表之間的依賴關(guān)系等可視化操作。但是不能進(jìn)行數(shù)據(jù)的增刪改查誊涯,增刪改查需要代碼中自行實(shí)現(xiàn)挡毅。這里我們創(chuàng)建了名為User(用戶)和Department(部門)兩張表

2.相關(guān)設(shè)置

3.設(shè)置完表的屬性以及關(guān)系后,為每張表創(chuàng)建model暴构。如圖所示跪呈,創(chuàng)建完成后左邊文件列表中會(huì)多每張表對(duì)應(yīng)的兩個(gè)文件(iOS7.0以后每張表對(duì)應(yīng)四個(gè)文件)


3.創(chuàng)建表的model文件

4.至此,CoreData基本配置已經(jīng)完成取逾,User表和Department表之間也已經(jīng)建立起聯(lián)系耗绿,點(diǎn)擊style可以看到每張表的Attributes及表之間Relationships。

4.表的關(guān)系圖

5.如果你熟悉Sqlite砾隅,那么接下來我們要做的就是鍵入代碼進(jìn)行數(shù)據(jù)的增刪改查误阻,實(shí)現(xiàn)增刪改查之前,我們需要先認(rèn)識(shí)幾個(gè)核心類晴埂。

NSManagedObjectContext: (管理對(duì)象上下文) 負(fù)責(zé)應(yīng)用和數(shù)據(jù)庫之間的交互

NSPersistentStoreCoordinator: (持久化存儲(chǔ)協(xié)調(diào)器)處理數(shù)據(jù)存儲(chǔ)的連接

NSManagedObjectModel: (對(duì)象模型) 代表CoreData模型文件,相當(dāng)于實(shí)體

NSEntityDescription: (實(shí)體結(jié)構(gòu)) 用來描述實(shí)體

NSPredicate: (查詢條件) 相當(dāng)于Sqlite中的Sql語句

NSFetchRequest: (數(shù)據(jù)請(qǐng)求) 可以給request設(shè)置請(qǐng)求的條件

如何對(duì)已經(jīng)建好實(shí)體表進(jìn)行增刪改查究反?最好的方法是自己再封裝一個(gè)單利類,該類能夠提供表名查詢方法儒洛,傳入某張表名后奴紧,我們便可以利用上述的幾個(gè)核心類提供的一系列方法創(chuàng)建數(shù)據(jù)的實(shí)例變量并讀寫進(jìn)表內(nèi),如果你是新建的工程項(xiàng)目并勾選了Use Core Data選項(xiàng)晶丘,那么AppDelegate類會(huì)自動(dòng)生成一些CoreData的管理方法(這些方法在你自己封裝過程中可以借鑒)供我們直接使用∈虻現(xiàn)僅以User表舉例實(shí)現(xiàn)增刪改查,以下.m文件里包含了四個(gè)xib創(chuàng)建的Button的回調(diào)浅浮,當(dāng)你點(diǎn)擊按鈕后沫浆,分別會(huì)向User表增刪改查某個(gè)用戶的個(gè)人信息。

//ViewController.m

#import "ViewController.h"
#import "User.h"
#import "AppDelegate.h"
#import <CoreData/CoreData.h>

@interface ViewController()

@property(nonatomic,strong)AppDelegate *app;


@end



@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.app = [UIApplication sharedApplication].delegate;   
}

//insert增
- (IBAction)coreDataInsert {
    //1.初始化一個(gè)user數(shù)據(jù)
    User *user = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:self.app.managedObjectContext];
    user.name = @"lcc";
    user.sex= @"boy";
    user.age = @15;
    
    //2.保存
    [self.app.managedObjectContext save:nil];
}

//delete刪
- (IBAction) coreDataDelete {
    //1.讀取所有用戶
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.app.managedObjectContext];
    
    //2.建立請(qǐng)求
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    [request setEntity:entity];
    
    //3.設(shè)置查找條件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name =%@",@"lcc"];
    [request setPredicate:predicate];
    
    //4.遍歷user表滚秩,找到該用戶后专执,刪除對(duì)象
    NSArray *array = [self.app.managedObjectContext executeFetchRequest:request error:nil];
    if(array.count){
        for(User *newUser in array){
            //刪除該用戶
            [self.app.managedObjectContext deleteObject:newUser];
        }
        //保存結(jié)果
        [self.app.managedObjectContext save:nil];
        NSLog(@"刪除成功");
    }else{
        NSLog(@"未找到該用戶數(shù)據(jù)");
    }
    
}

//upDate改
- (IBAction) coreDataUpdate {
    //1.讀取所有用戶
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.app.managedObjectContext];
    
    //2.建立請(qǐng)求
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    [request setEntity:entity];
    
    //3.設(shè)置查找條件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@",@"lcc"];
    [request setPredicate:predicate];
    
    //4.遍歷user表,找到該用戶后郁油,修改對(duì)象
    NSArray *array = [self.app.managedObjectContext executeFetchRequest:request error:nil];
    if(array.count){
        for(User *newUser in array){
            //修改該用戶
            newUser.name = @"lcc2";
        }
        //保存結(jié)果
        [self.app.managedObjectContext save:nil];
        NSLog(@"修改成功");
    }else{
        NSLog(@"未找到該用戶數(shù)據(jù)");
    }
}

//select查
- (IBAction) coreDataSelect {
    //1.讀取User表
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"User"inManagedObjectContext:self.app.managedObjectContext];
    
    //2.建立請(qǐng)求
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    [request setEntity:entity];
    
    //3.遍歷所有用戶本股,取出相關(guān)用戶
    NSArray *array = [self.app.managedObjectContext executeFetchRequest:request error:nil];
    for (User *user in array){
        NSLog(@"%@",user.name);
    }
}
@end

如此一來,我們便可以實(shí)現(xiàn)已經(jīng)實(shí)體化的User表的增刪改查桐腌,當(dāng)然拄显,這里的增刪改查相當(dāng)簡(jiǎn)便,實(shí)際項(xiàng)目中要進(jìn)行各種情況判斷案站,數(shù)據(jù)庫操作成功失敗會(huì)有返回信息躬审,該信息應(yīng)該反饋給用戶。此外,因?yàn)镃oreData并不是線程安全的承边,如果你希望自己封裝一個(gè)單利類遭殉,那么必須要考慮到數(shù)據(jù)庫的并發(fā)操作。

為什么要使用CoreData博助?
  • CoreData脫離了Sql語句险污,集成化更高。實(shí)際上富岳,一個(gè)成熟的工程中一定是對(duì)數(shù)據(jù)持久化進(jìn)行了封裝的蛔糯,應(yīng)該避免在業(yè)務(wù)邏輯中直接編寫Sql語句。
  • CoreData對(duì)版本遷移支持的較好城瞎,App升級(jí)之后數(shù)據(jù)庫字段或者表有更改會(huì)導(dǎo)致crash渤闷,CoreData的版本管理和數(shù)據(jù)遷移變得非常有用疾瓮,手動(dòng)寫sql語句操作相對(duì)麻煩一些脖镀。
  • CoreData不光能操縱SQLite,CoreData和iCloud的結(jié)合也很好狼电,如果有這方面需求的話優(yōu)先考慮CoreData蜒灰。
  • CoreData是支持多線程的,但需要thread confinement的方式實(shí)現(xiàn)肩碟,使用了多線程之后可以最大化的防止阻塞主線程强窖。

四.Sqlite(關(guān)鍵詞:靈活)

什么是Sqlite?

Sqlite是iPhone自帶的的數(shù)據(jù)庫管理系統(tǒng)。如果你對(duì)數(shù)據(jù)庫和Sql語句不陌生削祈,那么在介紹完CoreData后翅溺,你一定不滿足CoreData,作為一個(gè)程序員髓抑,也許你更希望能夠直接操作數(shù)據(jù)庫咙崎。既然蘋果選擇Sqlite作為數(shù)據(jù)庫,自然也提供了一系列可以直接操作它的函數(shù)(C語言函數(shù))吨拍,利用這些函數(shù)你完全能夠自己封裝一個(gè)sqlite數(shù)據(jù)庫框架褪猛,但同時(shí)你必須熟悉sql語句以及C語言語法。我在gitHub上上傳了一個(gè)自己封裝的輕量級(jí)Sqlite框架LCCSqliteManager 羹饰。目前版本只實(shí)現(xiàn)了一些基本的數(shù)據(jù)庫功能伊滋,如果感興趣你可以參考一下。

如何直接操作Sqlite队秩?

libsqlite3.0這個(gè)函數(shù)庫提供了許多C語言函數(shù)用于直接操作Sqlite笑旺,你的項(xiàng)目中導(dǎo)入該函數(shù)庫即可,具體導(dǎo)入方法LCCSqliteManager的文檔中有說明馍资,這里不在過多詳述燥撞,僅介紹幾個(gè)核心函數(shù)。

/*
** 打開或創(chuàng)建數(shù)據(jù)庫
*  char * filePath : 文件路徑 (UTF-8) 
*  sqlite3 **ppDb  : 指向數(shù)據(jù)庫文件指針的指針 
*/
int sqlite3_open(const char* filePath, sqlite3** ppDb);

//你可以這樣調(diào)用該函數(shù)
sqlite3 *_sqlite;
NSString *filePath = [NSHomeDirectory()stringByAppendingFormat: @"/Documents/%@.sqlite",filename];

int result = sqlite3_open([filePath UTF8String], &_sqlite);
if (result != SQLITE_OK) {
    NSLog(@"error:數(shù)據(jù)庫%@打開失敗",filename)
}
/*
** 關(guān)閉數(shù)據(jù)庫
sqlite3* : 指向該數(shù)據(jù)庫的指針
*/
int sqlite3_close(sqlite3*);
/*
** 創(chuàng)建一張表
*/
SQLITE_API int SQLITE_STDCALL sqlite3_exec(
  sqlite3*,                                  /* 非空數(shù)據(jù)庫指針 */
  const char *sql,                           /* 用于創(chuàng)建表的SQL語句 */
  int (*callback)(void*,int,char**,char**),  /* 回調(diào)函數(shù) */
  void *,                                    /* 第一個(gè)參數(shù)回調(diào) */
  char **errmsg                              /* 錯(cuò)誤信息 */
);

//第三、四個(gè)參數(shù)一般傳入NULL即可物舒。你可以這樣調(diào)用該函數(shù)
char *error = NULL;
sqlite3 *_sqlite;
NSString *targetSql = @"CREATE TABLE User(name TEXT,age INT,SEX TEXT)"
int result = sqlite3_exec(_sqlite, [targetSql UTF8String], NULL, NULL, &error);
if (result != SQLITE_OK) {
    NSLog(@"創(chuàng)建表失敗:%s", error);
    return NO;
}
/*
** 預(yù)編譯sql語句
*/
  int sqlite3_prepare_v2(
  sqlite3 *db,            /* 非空數(shù)據(jù)庫指針 */
  const char *zSql,       /* 要執(zhí)行的SQL語句 */
  int nByte,              /* zSql字節(jié)的最大長(zhǎng)度 */
  sqlite3_stmt **ppStmt,  /* 能夠使用sqlite3_step()執(zhí)行的編譯好的準(zhǔn)備語句的指針 */ 
  const char **pzTail     /* 超過zSql最大長(zhǎng)度的的剩余部分*/
);

/*
** 執(zhí)行預(yù)編譯好的sql語句色洞。
*/
int sqlite3_step(sqlite3_stmt*);

/*
** 釋放內(nèi)存。
*/
int sqlite3_finalize(sqlite3_stmt *pStmt);


上述三個(gè)方法配套使用冠胯,一般在含有查找操作的sql語句時(shí)都需要預(yù)編譯后再執(zhí)行火诸,并且手動(dòng)釋放內(nèi)存。

上面的方法比較常用荠察,表的刪除和修改操作因?yàn)槎夹枰檎也僮髦檬瘢孕枰猻qlite3_prepare_v2 和sqlite3_step配合使用,sqlite3_exec同樣可以執(zhí)行sql語句悉盆,因?yàn)樵黾雍筒檎覕?shù)據(jù)一般不需要預(yù)編譯盯荤。兩者具體的區(qū)別這里不在過多闡述,讀者可以根據(jù)參數(shù)的不同自行理解焕盟,或者查找網(wǎng)上有關(guān)libsqlite3.0函數(shù)庫的相關(guān)技術(shù)博客秋秤,該函數(shù)庫的大部分函數(shù)以及參數(shù)作用都有詳細(xì)解釋。

Sqlite和CoreData相比的優(yōu)劣

  • 直接操作Sqlite更容易理解數(shù)據(jù)的存儲(chǔ)方式脚翘,靈活度更高灼卢。
  • 在大量數(shù)據(jù)的批量讀寫速度上,Sqlite占有優(yōu)勢(shì)来农。
  • Sqlite需要自己寫Sql語句鞋真,且多線程、批量操作等都需要代碼實(shí)現(xiàn)沃于。

總結(jié)

本文大致介紹了iOS的四種數(shù)據(jù)持久化方式涩咖,且對(duì)他們之間的關(guān)系進(jìn)行了一定講解,筆者在封裝過LCCSqliteManager后繁莹,反而更傾向于使用CoreData檩互,因?yàn)槠涓€(wěn)定便捷,而大部分項(xiàng)目中蒋困,NSUSerDefaults與CoreData基本可以滿足數(shù)據(jù)持久化需求盾似,所以筆者較為推薦。

最后感謝閱讀雪标,也歡迎提出寶貴意見或糾正錯(cuò)誤零院。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市村刨,隨后出現(xiàn)的幾起案子告抄,更是在濱河造成了極大的恐慌,老刑警劉巖嵌牺,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件打洼,死亡現(xiàn)場(chǎng)離奇詭異龄糊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)募疮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門炫惩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阿浓,你說我怎么就攤上這事他嚷。” “怎么了芭毙?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵筋蓖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我退敦,道長(zhǎng)粘咖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任侈百,我火速辦了婚禮瓮下,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘设哗。我一直安慰自己唱捣,他們只是感情好两蟀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布网梢。 她就那樣靜靜地躺著,像睡著了一般赂毯。 火紅的嫁衣襯著肌膚如雪战虏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天党涕,我揣著相機(jī)與錄音烦感,去河邊找鬼。 笑死膛堤,一個(gè)胖子當(dāng)著我的面吹牛手趣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肥荔,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绿渣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了燕耿?” 一聲冷哼從身側(cè)響起中符,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎誉帅,沒想到半個(gè)月后淀散,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體右莱,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年档插,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慢蜓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡郭膛,死狀恐怖胀瞪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饲鄙,我是刑警寧澤凄诞,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站忍级,受9級(jí)特大地震影響帆谍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轴咱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一汛蝙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧朴肺,春花似錦窖剑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鞍盗,卻和暖如春需了,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背般甲。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工肋乍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敷存。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓墓造,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锚烦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子觅闽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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

  • 一、文件 應(yīng)用程序包 : 這里面存放的是應(yīng)用程序的源文件挽牢,包括資源文件和可執(zhí)行文件谱煤。NSString *path ...
    今天又要上班嗎閱讀 597評(píng)論 0 2
  • iOS數(shù)據(jù)持久化方式 文件 歸檔(NSKeyedArchiver) 屬性列表(NSUserDefaults) 數(shù)據(jù)...
    向陽的向日葵花閱讀 899評(píng)論 0 12
  • 在程序開發(fā)中,數(shù)據(jù)層永遠(yuǎn)是程序的核心結(jié)構(gòu)之一禽拔。我們將現(xiàn)實(shí)事物進(jìn)行抽象刘离,使之變成一個(gè)個(gè)數(shù)據(jù)室叉。對(duì)這些數(shù)據(jù)的加工處理是代...
    sindri的小巢閱讀 16,831評(píng)論 13 85
  • 在程序開發(fā)中,數(shù)據(jù)層永遠(yuǎn)是程序的核心結(jié)構(gòu)之一硫惕。我們將現(xiàn)實(shí)事物進(jìn)行抽象茧痕,使之變成一個(gè)個(gè)數(shù)據(jù)。對(duì)這些數(shù)據(jù)的加工處理是代...
    帥不過oneS閱讀 600評(píng)論 0 1
  • “優(yōu)秀的HR應(yīng)該具備哪些技能恼除?”踪旷,剛拿到這個(gè)題目的時(shí)候有些頭疼,雖然這個(gè)題目有些寬豁辉,但確實(shí)是個(gè)征文的好題目令野,...
    奇羽先森閱讀 616評(píng)論 0 2