iOS開發(fā)中的4種數(shù)據(jù)持久化方式【二囤踩、數(shù)據(jù)庫 SQLite3、Core Data 的運用】

** 在上文晓褪,我們介紹了ios開發(fā)中的其中2種數(shù)據(jù)持久化方式:屬性列表、歸檔解檔综慎。
本節(jié)將繼續(xù)介紹另外2種iOS持久化數(shù)據(jù)的方法:數(shù)據(jù)庫 SQLite3涣仿、Core Data 的運用;**
在本節(jié)示惊,將通過對4個文本框內(nèi)容的創(chuàng)建好港、修改,退出后臺米罚,再重新回到后臺钧汹,來認識這兩種持久化數(shù)據(jù)的方式。效果圖如下【圖1】:


【圖1 GUI界面效果圖】
【本次開發(fā)環(huán)境: Xcode:7.2 iOS Simulator:iphone6 By:啊左】
(本節(jié)2個項目demo的下載:數(shù)據(jù)庫SQLite3的運用Demo录择、Core Data 的運用Demo

一拔莱、數(shù)據(jù)庫SQLite3
SQLite(Strutcured Query Language,結(jié)構(gòu)化查詢語言)隘竭,是iOS的嵌入式SQL數(shù)據(jù)庫塘秦,在存儲和檢索大量數(shù)據(jù)方面非常有效,屬于輕量級數(shù)據(jù)庫动看,但是功能很強大尊剔。 安卓和iOS開發(fā)使用的都是SQLite數(shù)據(jù)庫。 而另一種持久化數(shù)據(jù)方式菱皆,Core Data是對SQLite的封裝须误,因為iOS中使用的SQLite是純C語言的。

1仇轻、鏈接到SQLite3庫
在Xcode中京痢,使用Single View Application模板創(chuàng)建一個新項目,命名為persistence3拯田。
新建項目選中項目導(dǎo)航列表(最左邊)的頂部然后在主區(qū)域的TARGETS部分選中persistence3历造,注意要從TARGETS選中而不是從PROJECT部分。
選中后,點擊“Build Phases”吭产,打開在第三欄侣监,按“+”添加“l(fā)ibsqlite3.0.tbd”【注意:Xcode7后dylib后綴改成tbd,如果仍要添加.bylib為后綴的鏈接臣淤,在添加framework那個對話框橄霉,最下面有個 "add other..." 點開之后, 按command+shift+G 邑蒋, 路徑輸入 /usr/lib/ 姓蜂,然后 找到你需要的lib文件 就ok了。医吊。 好吧钱慢,我還是習(xí)慣添加.dyib...】


【圖2 鏈接SQLite3.dyib】
3是版本號,是SQLite的第三個版本卿堂。它是始終指向最新版本的SQLite3庫的束莫;

在“Main.storyboard”中拖入4個標簽、4個文本框控件草描,拖動并對齊標簽與文本框览绿,并依次修改標簽文本如【圖1】,“ViewController.h”中添加一個裝載4個文本框的數(shù)組“lineFields”:

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic,strong)IBOutletCollection(UITextField) 
NSArray *lineFields;   //存儲4個文本框字段的數(shù)組
@end

然后打開輔助編輯器穗慕,通過control鍵將4個文本框連接到 lineFields 這個數(shù)組饿敲,確保連接順序為從頂部到底部!

在項目導(dǎo)航面板中逛绵,點擊"ViewController.m" ,將以下2段代碼添加到@implementation@end 的中間怀各,與上文相同,這個方法在后面會一直調(diào)用:

#import "ViewController.h"
#import <sqlite3.h>   //導(dǎo)入SQLite3术浪,注意是擴折號
//SQLite 是不區(qū)分大小寫的
@implementation ViewController{ 
sqlite3 *sqlite; //數(shù)據(jù)庫
}

//懶加載
-(NSString *)datafilePath{ 
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *path = [array objectAtIndex:0]; 
return [path stringByAppendingPathComponent:@"data.sqlite"];
}

在這里渠啤,我們介紹一下iOS9的一個新的變化:UIAlertController。小小地在這里運用一下:

//警告提示框添吗,為后面的操作向用戶提示信息
-(void)alert:(NSString *)mes{ 
/*知識點:ios 9.0 后沥曹,簡單的UIAlertView已經(jīng)不能用了。 UIAlertController代替了UIAlertView彈框 和 UIActionSheet下彈框 */ 
//UIAlertControllerStyleAlert:中間碟联; UIAlertControllerStyleActionSheet:顯示在屏幕底部妓美; 
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"警告" message:mes preferredStyle:(UIAlertControllerStyleAlert)]; 
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:(UIAlertActionStyleCancel) handler:nil]; 
UIAlertAction *defult = [UIAlertAction actionWithTitle:@"確定" style:(UIAlertActionStyleDefault) handler:nil]; 
[alert addAction:cancel]; 
[alert addAction:defult];
[self presentViewController:alert animated:YES completion:nil]; 
//呈現(xiàn)
}
  • (void)viewDidLoad 以及通知的方法代碼:
 1 - (void)viewDidLoad { 
2  [super viewDidLoad]; 
3 int result = sqlite3_open([[self datafilePath]UTF8String], &sqlite); 
4 //不等于SQLITE_OK,則表示打開數(shù)據(jù)庫的時候遇到問題 
5 if(result != SQLITE_OK) 
6  { 
7  sqlite3_close(sqlite); 
8 [self alert:@"數(shù)據(jù)庫打開失敗"]; 
9  }
10 
11 //定義一個語句鲤孵,其中if not exists表示:如果不存在數(shù)據(jù)表壶栋,則新建一個。 若存在普监,則此命令自動退出. 所以這個語句可以在每次啟動時調(diào)用
12 NSString *createSql = @"CREATE TABLE IF NOT EXISTS 'wenbenkuang'(id INTEGER PRIMARY KEY,datatext TEXT NOT NULL)";
13 char * error;
14 int ret = sqlite3_exec(sqlite,[createSql UTF8String], NULL, NULL, &error); //SQLite是純C語言的贵试。SQL語句需要使用“UTF8String”方法把NSString轉(zhuǎn)換為char.
15 if(ret != SQLITE_OK)
16  {
17 [self alert:[NSString stringWithFormat:@"數(shù)據(jù)表創(chuàng)建失敗%s",error]];
18  }
19 
20 //使用select語句加載數(shù)據(jù)琉兜,并要求數(shù)據(jù)庫按行號準備排序,以便我們以相同的順序獲取毙玻,否則將使用sqlite3內(nèi)部存儲順序
21 NSString *preSql = @"SELECT id,datatext FROM 'wenbenkuang'ORDER BY id";
22 sqlite3_stmt *statmt;
23 if(sqlite3_prepare_v2(sqlite,[preSql UTF8String], -1, &statmt, nil) == SQLITE_OK) //SQLITE_OK表成功加載
24  {
25 while (sqlite3_step(statmt) == SQLITE_ROW) 
26  {
27 int row = sqlite3_column_int(statmt, 0); //獲取行號
28 char *rowData = (char *)sqlite3_column_text(statmt, 1); //獲取該行數(shù)據(jù)
29 NSString *dataString = [[NSString alloc]initWithUTF8String:rowData];
30 UITextField *textfield = self.lineFields[row];
31 textfield.text = dataString;
32  }
33 //完成陳述
34  sqlite3_finalize(statmt);
35  }
36 //關(guān)閉數(shù)據(jù)庫
37  sqlite3_close(sqlite);
38 
39 //注冊一個觀測者豌蟋,進入后臺時發(fā)送通知;
40 UIApplication *app = [UIApplication sharedApplication];
41 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationWillResignActiveNotification:)  name:UIApplicationWillResignActiveNotification object:app];
42 }
43 -(void)applicationWillResignActiveNotification:(NSNotification *)notification
44 {
45 int result = sqlite3_open([[self datafilePath] UTF8String], &sqlite);
46 if (result != SQLITE_OK) {
47 [self alert:@"數(shù)據(jù)庫打開失敗"];
48  sqlite3_close(sqlite);
49  }
50 for(int i=0;i<4;i++)
51  {
52 UITextField *tetxField = self.lineFields[i];
53 char *updataSql = "INSERT OR REPLACE INTO 'wenbenkuang'(id,datatext) VALUES(?,?);";
54 sqlite3_stmt *stmt;
55 if(sqlite3_prepare_v2(sqlite, updataSql, -1, &stmt, nil) == SQLITE_OK)
56  {
57 sqlite3_bind_int(stmt, 1, i);
58 sqlite3_bind_text(stmt, 2, [tetxField.text UTF8String], -1, NULL);
59  }
60 if(sqlite3_step(stmt) != SQLITE_DONE)
61  {
62 [self alert:@"數(shù)據(jù)更新失敗"];
63  }
64  sqlite3_finalize(stmt);
65  }
66  sqlite3_close(sqlite);
67 }

在這段的viewDidLoad代碼中:
(行號為3-9)我們首先創(chuàng)建或者打開數(shù)據(jù)庫,如果打開時遇到問題桑滩,則拋出警告框梧疲。
(行號為11-18)數(shù)據(jù)庫將所有的數(shù)據(jù)存儲在表中。因此运准,創(chuàng)建一個名為“wenbenkuang”數(shù)據(jù)表幌氮,包含一個標識為“id”的鍵,與一個名為"datatext"的不為空的文本項胁澳,如果已存在相同名稱的表该互,則退出創(chuàng)建,不執(zhí)行操作韭畸,所以該數(shù)據(jù)庫語句可以在每次啟動時調(diào)用一次慢洋,而不會影響到現(xiàn)有的數(shù)據(jù)庫;【SQLite是純C語言的陆盘。SQL語句需要使用“UTF8String”方法把NSString轉(zhuǎn)換為char.】

(行號為20-23)加載數(shù)據(jù),使用select語句加載數(shù)據(jù)败明,并要求數(shù)據(jù)庫按行號準備排序隘马,以便我們以相同的順序獲取,否則將使用sqlite3內(nèi)部存儲順序妻顶;

(行號為25-32)遍歷返回各行酸员,定義一個int和char獲取數(shù)據(jù),然后讳嘱,我們通過從數(shù)據(jù)庫獲取的數(shù)據(jù)設(shè)置我們的文本字段幔嗦。

最后,關(guān)閉數(shù)據(jù)庫沥潭,操作結(jié)束邀泉;

在 “applicationWillResignActiveNotification:” 方法中,我們也是首先打開數(shù)據(jù)庫钝鸽,創(chuàng)建一個字段名稱汇恤,以便檢測到輸出,然后設(shè)計一條帶2個綁定變量的INSERT OR REPLACE的SQL語句拔恰,第一變量表行因谎,第二個表存儲的實際字段值,接下來聲明一個指向語句的指針颜懊,為語句添加綁定變量财岔,并將值綁定到2個綁定標量中风皿,
通過調(diào)用sqlite3_step來執(zhí)行更新,循環(huán)執(zhí)行該語句匠璧。
完成后桐款,關(guān)閉操作數(shù)據(jù)庫;接下來我們運行調(diào)試一下患朱。

按“command+R”運行程序鲁僚,為4個文本框輸入字段,關(guān)閉Xcode裁厅,或按下“command+shift”冰沙,點擊2次“H”鍵,退出該應(yīng)用执虹,然后再次打開拓挥,
看看是是否文本框中保留有原來自己的輸入的字段。

二袋励、Core Data的運用

首先侥啤,我們需要注意的是,Core Data是iOS上一個能夠提高效率的數(shù)據(jù)庫框架茬故,但Core Data不是一種數(shù)據(jù)庫盖灸,它的底層還是利用Sqlite3來存儲數(shù)據(jù)的。
同樣的磺芭,這次我們依然通過創(chuàng)建一個簡單的persistence應(yīng)用赁炎,來展示如何通過蘋果自帶的Core Data框架來實現(xiàn)持久化。
第一步钾腺,我們應(yīng)該很熟悉了徙垫。在Xcode中,使用Single View Application模板創(chuàng)建一個新項目放棒,命名為persistence4姻报。
如【圖3】,先別按Next间螟,勾選“Use Core Data”吴旋,其中“Devices”為設(shè)備選項,你可以選擇“iphone”或者“ipad”厢破,這里我們選擇通用“Universal”邮府。點擊Next!


【圖3 創(chuàng)建persistence4】
這次在敲入代碼前溉奕,我們還需要進行一系列的討論褂傀,好吧。加勤。仙辟⊥ǎ“Core Data”確實麻煩些。
1叠国、Core Data的數(shù)據(jù)模型
之前未檩,如上文的iOS開發(fā)中的4種數(shù)據(jù)持久化方式【一、屬性列表與歸檔解檔】所介紹的粟焊,在使用Core Data之前我們創(chuàng)建數(shù)據(jù)模型的方式便是創(chuàng)建一個NSObject的子類并讓它們遵循NSCoding和NSCopying協(xié)議冤狡,以便能夠?qū)λ鼈冞M行歸檔解檔。但是项棠,在Core Data中悲雳,我們使用了不同方式,不需要創(chuàng)建一個新子類香追,而是先在數(shù)據(jù)模型中創(chuàng)建實體(Entity)合瓢,然后在代碼中為這些實體創(chuàng)建托管對象(Managed Object)
實體透典,就是對對象的描述晴楔; 托管對象,表示在運行的過程該實體的具體實例峭咒;
(可以這么理解:實體税弃、托管對象之間的關(guān)系類似于類與類的對象;)

2凑队、鍵-值編碼形式
在我們使用NSDictionary的時候则果,就已經(jīng)使用到這種編碼的形式了,但與NSDictionary相比顽决,Core Data會復(fù)雜一些,只是基本概念是相同的导匣。具體的操作方法如下:
首先定義一個托管對象: NSManagedObject *managedObject;
那么才菠,就可以通過相應(yīng)的方法獲取name特性的數(shù)據(jù)值了:NSString *nameData = [managedObject valueForKey:@"name"];
為name特性設(shè)置新的屬性值:[managedObject setValue:@"newNameData" forKey:@"name"];

3、動手:模型的創(chuàng)建贡定。
在左邊的項目導(dǎo)航面板上面單擊“persistence4.xcdatamodeld”文件赋访,此時打開了Xcode的數(shù)據(jù)模型編輯器,編輯器的面板中已經(jīng)列出了數(shù)據(jù)模型中的所有實體缓待、獲取請求和配置蚓耽。
由于我們還未創(chuàng)建數(shù)據(jù)模型,因此列表是空的旋炒,單擊實體面板左下方的加號圖標(Add Entity)步悠,此時創(chuàng)建了一個名為:“Entity”的實體:



(提醒一下的是,右下角的“Editor Style”選項:table視圖和graph視圖瘫镇。這兩種視圖在數(shù)據(jù)模型上沒有區(qū)別鼎兽,只是顯示的方式不同而已答姥。如果你的模型里面包含多個實體,那么graph視圖的顯示方式會非常有用谚咬,它以圖形化的方式呈現(xiàn)了所有實體之間的關(guān)系鹦付;由于table視圖顯示了當(dāng)前實體更為詳細的信息,因為我們在創(chuàng)建這個實體的時候择卦,還是選用默認的table實體)

然后點擊該實體敲长,在右邊的數(shù)據(jù)模型編輯器上面,把第一個name字段改為我們接下來使用的“Line”字段秉继,所以我們這樣就算創(chuàng)建了一個名為“Line”的實體了祈噪。


接下來就為“Line”實體添加新特性,單擊并按住右下角的加號圖標“Add Attribute”秕噪,當(dāng)然添加特性的話也可以直接點擊“+”圖標就可以了钳降,這里只是為了方便讀者看到該選項所表達的意思。


點擊“+”后腌巾,可以看到新增了一個名為“attribute”的特性遂填,把它修改為“l(fā)ineNumber”,修改Type為“Interger16”澈蝙,并把右邊圈紅的Optional取消選中狀態(tài)吓坚。


再次單擊“+”,把新特性修改為“l(fā)ineText”灯荧,修改Type為“String”礁击,這里的Optional默認勾選(該選項用于防止我們創(chuàng)建的“l(fā)ineText”文本在用戶給定的字段為空,而“l(fā)ineNumber”表行號逗载,行號不會出現(xiàn)為空的情況哆窿,)


下面是代碼部分,與SQLite的創(chuàng)建類似:
在“Main.storyboard”中拖入2個標簽厉斟、2個文本框控件挚躯,拖動并對齊標簽與文本框,并依次修改標簽文本如【圖1】擦秽,“ViewController.h”中添加一個裝載2個文本框的數(shù)組“lineFields”:

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic,strong)IBOutletCollection(UITextField) 
NSArray *lineFields; //存儲2個文本框字段的數(shù)組
@end

然后打開輔助編輯器码荔,通過control鍵將2個文本框連接到 lineFields 這個數(shù)組,確保連接順序為從頂部到底部感挥!
單擊“AppDelegate.h”缩搅,我們能夠已經(jīng)包含了數(shù)據(jù)類型定義需要的代碼了,我們做一些注釋:

//COREDATA托管上下文
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
//托管模型
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
//存儲時(持久化)協(xié)調(diào)者
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
//保存托管上下文
- (void)saveContext;
//取得當(dāng)前應(yīng)用程序文檔路徑
- (NSURL *)applicationDocumentsDirectory;

點擊“ViewController.m”触幼,下面硼瓣,我們進行一連串的代碼:

 1 #import "ViewController.h" 
2 #import "AppDelegate.h" //需要導(dǎo)入app代理類 
3  
4 static NSString *const Zline = @"Line"; 
5 static NSString *const ZlineNumber = @"lineNumber"; 
6 static NSString *const ZlineText = @"lineText"; 
7  
8 @implementation ViewController 
9 
10 - (void)viewDidLoad {
11  [super viewDidLoad];
12 //獲取應(yīng)用程序代理
13 AppDelegate *appDe = [UIApplication sharedApplication].delegate;
14 //獲取托管對象上下文(此時如果數(shù)據(jù)庫不存在就不會創(chuàng)建數(shù)據(jù)庫)
15 NSManagedObjectContext *context = [appDe managedObjectContext];
16 //創(chuàng)建請求(并傳遞實體描述“l(fā)ine”給它)
17 NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:Zline];
18 //通過上下文context執(zhí)行請求request,獲取記錄對象的數(shù)組
19 NSArray *objetcs = [context executeFetchRequest:request error:nil];
20 if(objetcs == nil) //確保返回的是有效的數(shù)組
21  {
22 NSLog(@"數(shù)組創(chuàng)建失敗");
23  }
24 //分別提取每個托管對象保存的數(shù)據(jù)
25 for(NSManagedObject *managed in objetcs)
26  {
27 //獲取行號(注意轉(zhuǎn)換為int)
28 int lineNum = [[managed valueForKey:ZlineNumber] intValue];
29 //獲取文本
30 NSString *lineText = [managed valueForKey:ZlineText];
31 
32 UITextField *textField = self.lineFields[lineNum];
33 textField.text = lineText;
34  }
35 
36 //后臺處理
37 UIApplication *app = [UIApplication sharedApplication];
38 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(applicationWillResignActiveNotification:) name: UIApplicationWillResignActiveNotification object:app];
39 }
40 
41 -(void)applicationWillResignActiveNotification:(NSNotification *)notification
42 {
43 AppDelegate *appDe = [UIApplication sharedApplication].delegate;
44 NSManagedObjectContext *context = appDe.managedObjectContext;
45 
46 for(int i =0;i<2;i++)
47  {
48 NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:Zline];
49 //predicate謂語置谦,創(chuàng)建請求巨双,但是為確認存儲中是否已有一個與字段對應(yīng)的托管對象噪猾,創(chuàng)建謂語,是為了給字段標識正確的對象筑累。
50 request.predicate = [NSPredicate predicateWithFormat:@"(lineNumber=%d)",i]; //注意謂語的拼寫:@"(lineNumber = %d)",i
51 NSArray *objects = [context executeFetchRequest:request error:nil];
52 if(objects ==nil)
53  {
54 NSLog(@"無法獲得請求數(shù)據(jù)%");
55  }
56 
57 //因為我們不知道是要從存儲中加載托管對象袱蜡,還是創(chuàng)建新的托管對象,因此先創(chuàng)建空的托管對象
58 NSManagedObject *managed = nil;
59 if([objects count]>0) //檢查返回有效的對象慢宗,因此加載
60  {
61 managed = [objects objectAtIndex:0];
62  }
63 else //檢查到無有效對象坪蚁,因此創(chuàng)建新的托管對象
64  {
65 //創(chuàng)建實體、插入托管對象到獲取的上下文镜沽,我們直接用下面這句代碼敏晤,省去很多流程
66 managed = [NSEntityDescription insertNewObjectForEntityForName:Zline inManagedObjectContext:context];
67  }
68 UITextField *textField = self.lineFields[i];
69 //使用鍵-值碼方式更新設(shè)置行號和文本:
70  [managed setValue:[NSNumber numberWithInt:i] forKey:ZlineNumber];
71  [managed setValue:textField.text forKey:ZlineText];
72  }
73 //完成循環(huán)。
74 //最后一步:持久化數(shù)據(jù):
75  [appDe saveContext];
76 }
77
78 @end

我們解析一下上面的代碼缅茉,首先需要導(dǎo)入我們創(chuàng)建Core Data模型時Xcode創(chuàng)建的已有代碼的“AppDelegate.h”嘴脾。
(4-6行) :定義包括實體“Line”、行號“l(fā)ineNumber”蔬墩、文本“l(fā)ineText”等的字符段译打,方便我們后面的代碼編寫;(記得別拼錯拇颅,別問我為什么怎么說...我就是剛剛在演示的時候一直報錯奏司,才發(fā)現(xiàn)原來只是字符串拼錯了...555..心疼啊左);
(12-23行): 通過上下文context,執(zhí)行請求request獲取記錄對象的數(shù)組樟插。并確認數(shù)組有效韵洋。
(24-34行):分別提取每個托管對象保存的數(shù)據(jù),并賦值給對應(yīng)行號的文本框文本字段黄锤;
(36-39行):后臺處理
(48-55行):執(zhí)行帶有謂語的請求搪缨。
(57-71行):分托管對象是否已經(jīng)存在2種情況,進行編碼設(shè)置行號和文本
(75行): 持久化數(shù)據(jù)(記得帶上這行代碼)

好了鸵熟,關(guān)于Core Data數(shù)據(jù)模型和GUI界面副编,以及代碼我們已經(jīng)設(shè)計編寫完畢。
按“command+R”運行程序旅赢,為2個文本框輸入字段齿桃,關(guān)閉Xcode惑惶,或按下“command+shift”煮盼,點擊2次“H”鍵,退出該應(yīng)用带污,然后再次打開僵控,
如果運行沒有發(fā)生錯誤的話,那么我們已經(jīng)設(shè)計了一個簡單的Core Data儲存數(shù)據(jù)應(yīng)用“persistence4”了鱼冀。

至此报破,我們包括上文iOS開發(fā)中的4種數(shù)據(jù)持久化方式【一悠就、屬性列表與歸檔解檔】的演練,已經(jīng)為大家展示了有關(guān)iOS開發(fā)中的4種數(shù)據(jù)持久化方式充易。
希望能夠分享與讀者梗脾。
只是,對于這兩篇關(guān)于iOS開發(fā)數(shù)據(jù)持久化的所搭建的應(yīng)用"persistence"例子盹靴,也只是一個簡單的應(yīng)用炸茧,具體的應(yīng)用設(shè)計大家可以發(fā)揮創(chuàng)造力,讓數(shù)據(jù)持久化在移動開發(fā)應(yīng)用過程中更加便捷稿静。
當(dāng)然梭冠,更多更深入的數(shù)據(jù)持久化、數(shù)據(jù)處理改备,我們只懂得這些是遠遠不夠的控漠,需要我們通過網(wǎng)絡(luò)上共享的內(nèi)容以及自己工作學(xué)習(xí)中不斷積累,才能使這些知識點更加深入悬钳,更加適應(yīng)iOS開發(fā)工作盐捷。


(轉(zhuǎn)載請標明原文出處,謝謝支持 ~ - ~)
? by:啊左~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末他去,一起剝皮案震驚了整個濱河市毙驯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌灾测,老刑警劉巖爆价,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異媳搪,居然都是意外死亡铭段,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門秦爆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來序愚,“玉大人,你說我怎么就攤上這事等限“炙保” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵望门,是天一觀的道長形娇。 經(jīng)常有香客問我,道長筹误,這世上最難降的妖魔是什么桐早? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上哄酝,老公的妹妹穿的比我還像新娘友存。我一直安慰自己,他們只是感情好陶衅,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布屡立。 她就那樣靜靜地躺著,像睡著了一般搀军。 火紅的嫁衣襯著肌膚如雪侠驯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天奕巍,我揣著相機與錄音吟策,去河邊找鬼。 笑死的止,一個胖子當(dāng)著我的面吹牛檩坚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诅福,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼匾委,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了氓润?” 一聲冷哼從身側(cè)響起赂乐,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咖气,沒想到半個月后挨措,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡崩溪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年浅役,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伶唯。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡觉既,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乳幸,到底是詐尸還是另有隱情瞪讼,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布粹断,位于F島的核電站符欠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏姿染。R本人自食惡果不足惜背亥,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悬赏。 院中可真熱鬧狡汉,春花似錦、人聲如沸闽颇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兵多。三九已至尖啡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剩膘,已是汗流浹背衅斩。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怠褐,地道東北人畏梆。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像奈懒,于是被迫代替她去往敵國和親奠涌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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