我們知道儲(chǔ)存方式分為兩種:內(nèi)存 和 閃存邑退。內(nèi)存的存儲(chǔ)是臨時(shí)的竹宋,運(yùn)行時(shí)是有效的且效率很高,而閃存則是一種持久化儲(chǔ)存地技,但產(chǎn)生I/O消耗蜈七,效率相對(duì)低。我們把內(nèi)存中的數(shù)據(jù)轉(zhuǎn)移到閃存中進(jìn)行持久化的操作叫做歸檔莫矗。
然而兩者結(jié)合起來(lái)就是我們常用的數(shù)據(jù)存儲(chǔ)方法飒硅。通常我們所用到的:CoreData、SQLite作谚、NSUserDefaults等都是數(shù)據(jù)存儲(chǔ)的方法三娩。
- plist NSArray/NSDictionary
- NSCoding 歸檔反歸檔
- NSUserDefaults用于存儲(chǔ)配置信息
- SQLite用于存儲(chǔ)查詢需求較多的數(shù)據(jù)
- CoreData用于規(guī)劃應(yīng)用中的對(duì)象
輕量級(jí)本地?cái)?shù)據(jù)存儲(chǔ)
NSUserDefaults單例以key-value的形式存儲(chǔ)了一系列偏好設(shè)置,key是名稱妹懒,value是相應(yīng)的數(shù)據(jù)雀监。存/取數(shù)據(jù)時(shí)可以使用方法objectForKey:和setObject:forKey:來(lái)把對(duì)象存儲(chǔ)到相應(yīng)的plist文件中,或者讀取彬伦,既然是plist文件滔悉,那么對(duì)象的類型則必須是plist文件可以存儲(chǔ)的類型:NSNumber(NSInteger、float单绑、double)回官,NSString,NSDate搂橙,NSArray歉提,NSDictionary,BOOL.而如果需要存儲(chǔ)plist文件不支持的類型区转,比如圖片苔巨,可以先將其歸檔為NSData類型,再存入plist文件.
- 對(duì)相同的Key賦值約等于一次覆蓋废离,要保證每一個(gè)Key的唯一性
- NSUserDefaults 存儲(chǔ)的對(duì)象全是不可變的
保存在NSUserDefaults中的信息在你的應(yīng)用關(guān)閉后再次打開之后依然存在侄泽。保存信息到NSUserDefaults的一個(gè)例子就是保存用戶是否已登錄的狀態(tài)。我們把用戶的登錄狀態(tài)保存到NSUserDefaults以便用戶關(guān)閉應(yīng)用再次打開應(yīng)用的時(shí)候蜻韭,應(yīng)用能夠從NSUserDefaults獲取數(shù)據(jù)悼尾,根據(jù)用戶是否登錄展示不同的界面柿扣。有些應(yīng)用也用這個(gè)功能來(lái)保存機(jī)密數(shù)據(jù),比如用戶的訪問令牌闺魏,以便下次應(yīng)用登錄的時(shí)候未状,它們能夠使用這個(gè)令牌來(lái)再次認(rèn)證用戶。但是保存到NSUserDefaults的數(shù)據(jù)并沒有加密析桥,因此可以很容易的從應(yīng)用的包中看到司草。NSUserDefaults被存在一個(gè)以應(yīng)用的bundle id為名稱的plist文件中。
存儲(chǔ):
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *string = @"hahaha";
[user setObject:string forKey:@"myKey"];
[user synchronize];//寫完別忘了同步
讀扰菡獭:
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *value = [user objectForKey:@"myKey"];
SQLite
然而我們面對(duì)大量數(shù)據(jù)寫入的時(shí)候 輕量級(jí)儲(chǔ)存明顯不適用埋虹。SQLite的優(yōu)點(diǎn)就是他占用資源非常低,處理速度快娩怎。
SQLite是如何存儲(chǔ)的吨岭?
數(shù)據(jù)庫(kù)的存儲(chǔ)就像平時(shí)我們用的excel表格,它也是以表為單位峦树。橫縱分別對(duì)應(yīng)屬性名和自己的ID。
- 新建一個(gè)數(shù)據(jù)庫(kù)
- 新建一張表(table)
- 添加多個(gè)字段(column旦事,列魁巩,屬性)
- 添加多行記錄(row,每行存放多個(gè)字段對(duì)應(yīng)的值 三姐浮、SQL語(yǔ)句種類
- 數(shù)據(jù)定義語(yǔ)句(DDL:Data Definition Language) 包括create和drop等操作 在數(shù)據(jù)庫(kù)中創(chuàng)建新表或刪除表(create table或 drop table)
- 數(shù)據(jù)操作語(yǔ)句(DML:Data Manipulation Language) 包括insert谷遂、update、delete等操作 上面的3種操作分別用于添加卖鲤、修改肾扰、刪除表中的數(shù)據(jù)
- 數(shù)據(jù)查詢語(yǔ)句(DQL:Data Query Language) 可以用于查詢獲得表中的數(shù)據(jù) 關(guān)鍵字select是DQL(也是所有SQL)用得最多的操作 其他DQL常用的關(guān)鍵字有where锁孟,order by次绘,group by和having
libsqlite3.dylib與libsqlite3.0.dylib是不同的鳍置,libsqlite3.dylib是一個(gè)指向libsqlite3.0.dylib的索引沦寂,而且總是指向最新的sqlite3動(dòng)態(tài)庫(kù)羽历。(如果有新的libsqlite3.1.dylib出現(xiàn)則會(huì)指向3.1)
/**
* 單例方法實(shí)現(xiàn)
*
*/
+(instancetype)sharedDataBase {
static RYBaseHandle *baseHandle = nil;
if (baseHandle == nil) {
baseHandle = [[RYBaseHandle alloc] init];
}
return baseHandle;
}
/**
* 定義sqlite實(shí)例
*/
static sqlite3 *sqlite;
/**
* 打開數(shù)據(jù)庫(kù)
*/
-(void)openSqlite {
if (sqlite != nil) {
return;
}
NSString *dataPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
// pathComponent 路徑拼接不需要/
// stringByAppendingFormat 需要/
NSString *sqlitePath = [dataPath stringByAppendingPathComponent:@"favorite.db"];
// utf8
int result = sqlite3_open(sqlitePath.UTF8String, &sqlite);
if (result == SQLITE_OK) {
} else {
}
}
/**
* 創(chuàng)建表格
*/
-(void)createTableView {
NSString *tableSqlite = @"create table if not exists collect(keyid integer primary key autoincrement, title text, duration integer, RYdescription text, category text, playUrl text, coverForFeed text)";
int result = sqlite3_exec(sqlite, tableSqlite.UTF8String, NULL, NULL, NULL);
if (result == SQLITE_OK) {
} else {
}
}
以及增刪改查等語(yǔ)句:
更新SQL:
NSString *changeSql = [NSString stringWithFormat:@"update collect set title = '%@', duration = '%ld',RYdescription = '%@',category = '%@', playUrl = '%@', coverForFeed = '%@' where number = '%ld'",model.title,model.duration,model.RYdescription,model.category,model.playUrl,model.coverForFeed,number];
int result = sqlite3_exec(sqlite, changeSql.UTF8String, NULL, NULL, nil);
if (result == SQLITE_OK) {
} else {
}
插入:
NSString *insert = [NSString stringWithFormat:@"insert into collect(title,duration,RYdescription,category,playUrl,coverForFeed) values('%@','%ld','%@','%@','%@', '%@')",model.title,model.duration,model.RYdescription,model.category,model.playUrl,model.coverForFeed];
int result = sqlite3_exec(sqlite, insert.UTF8String, NULL, NULL, nil);
if (result == SQLITE_OK) {
} else {
}
查詢 [返回?cái)?shù)組]:
/**
* 創(chuàng)建數(shù)據(jù)庫(kù)跟隨指針烦磁,用來(lái)循環(huán)遍歷表格中的每一行
*/
NSString *selectSql = @"select * from collect";
sqlite3_stmt *stmt = nil;
/**
* 數(shù)據(jù)庫(kù)內(nèi)查詢
*
* @param sqlite 數(shù)據(jù)庫(kù)名稱
* @param selectSql.UTF8String 查詢
* @param -1 字?jǐn)?shù)限制 [-1 表示不限制]
* @param stmt 跟隨指針對(duì)象查詢
* @param nil 廓块?桃焕?亏钩?
*
* @return 查詢結(jié)果
*/
int result = sqlite3_prepare_v2(sqlite, selectSql.UTF8String, -1, &stmt, nil);
/**
初始化返回?cái)?shù)組
- returns: 可變數(shù)組
*/
NSMutableArray *array = [[NSMutableArray array] init];
if (result == SQLITE_OK) {
NSLog(@"查詢成功");
/**
* 逐行查詢
*/
while (sqlite3_step(stmt) == SQLITE_ROW) {
const unsigned char *title = sqlite3_column_text(stmt, 1);// column列/欄
int duration = sqlite3_column_int(stmt, 2);
const unsigned char *RYdescription = sqlite3_column_text(stmt, 3);
const unsigned char *category = sqlite3_column_text(stmt, 4);
const unsigned char *playUrl = sqlite3_column_text(stmt, 5);
const unsigned char *coverForFeed = sqlite3_column_text(stmt, 6);
RYModelMain *model = [[RYModelMain alloc] init];
model.title = [NSString stringWithUTF8String:(const char *)title];
model.duration = duration;
model.RYdescription = [NSString stringWithUTF8String:(const char *)RYdescription];
model.category = [NSString stringWithUTF8String:(const char *)category];
model.playUrl = [NSString stringWithUTF8String:(const char *)playUrl];
model.coverForFeed = [NSString stringWithUTF8String:(const char *)coverForFeed];
/**
* 將找到的數(shù)據(jù)放入數(shù)組中返回
*/
[array addObject:model];
}
} else {
}
查詢 [返回布爾值]
NSString *seleSql = @"select * from collect";
sqlite3_stmt *stmt = nil;
int result = sqlite3_prepare_v2(sqlite, seleSql.UTF8String, -1, &stmt, nil);
RYModelMain *model = [[RYModelMain alloc] init];
if (result == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
const unsigned char *title = sqlite3_column_text(stmt, 1);
model.title = [NSString stringWithUTF8String:(const char *)title];
}
} else {
}
if ([model.title isEqualToString:title]) {
return YES;
} else {
return NO;
}
刪除:
/**
* 創(chuàng)建刪除sql
*/
NSString *deleSql = [NSString stringWithFormat:@"delete from collect where title = '%@'",model.title];
int result = sqlite3_exec(sqlite, deleSql.UTF8String, NULL, NULL, nil);
if (result == SQLITE_OK) {
} else {
}
關(guān)閉數(shù)據(jù)庫(kù):
sqlite = nil;
int result = sqlite3_close(sqlite);
if (result == SQLITE_OK) {
} else {
}
以及刪除表格:
NSString *dropSql = @"drop table collect";
int result = sqlite3_exec(sqlite, dropSql.UTF8String, NULL, NULL, nil);
if (result == SQLITE_OK) {
} else {
}
CoreData
SQLite用起來(lái)太過于麻煩莲绰,有些固定的語(yǔ)句特別容易出錯(cuò),這也就是為什么蘋果鼓勵(lì)用CoreData姑丑。CoreData優(yōu)點(diǎn):能夠合理管理內(nèi)存蛤签,避免使用sql的麻煩,高效.
構(gòu)成:
- Managed Object Model:是描述應(yīng)用程序的數(shù)據(jù)模型栅哀,這個(gè)模型包含實(shí)體(Entity)震肮,特性(Property)称龙,讀取請(qǐng)求(Fetch Request)。
- Managed Object Context:參與對(duì)數(shù)據(jù)對(duì)象進(jìn)行各種操作的全過程钙蒙,并監(jiān)測(cè)數(shù)據(jù)對(duì)象的變化茵瀑,以提供對(duì) undo/redo 的支持及更新綁定到數(shù)據(jù)的 UI。
- Persistent Store Coordinator 相當(dāng)于數(shù)據(jù)文件管理器躬厌,處理底層的對(duì)數(shù)據(jù)文件的讀取與寫入马昨。
- Managed Object 數(shù)據(jù)對(duì)象,與 Managed Object Context 相關(guān)聯(lián)扛施。
- 圖中綠色的 Array Controller, Object Controller, Tree Controller 這些控制器鸿捧,一般都是通過 control+drag 將 Managed Object Context 綁定到它們,這樣我們就可以在 nib 中可視化地操作數(shù)據(jù)疙渣。
具體步驟:
- 應(yīng)用程序先創(chuàng)建或讀取模型文件(后綴為xcdatamodeld)生成 NSManagedObjectModel 對(duì)象匙奴。Document應(yīng)用程序是一般是通過 NSDocument 或其子類 NSPersistentDocument)從模型文件(后綴為 xcdatamodeld)讀取。
- 然后生成 NSManagedObjectContext 和 NSPersistentStoreCoordinator 對(duì)象妄荔,前者對(duì)用戶透明地調(diào)用后者對(duì)數(shù)據(jù)文件進(jìn)行讀寫泼菌。
- NSPersistentStoreCoordinator 負(fù)責(zé)從數(shù)據(jù)文件(xml, sqlite,二進(jìn)制文件等)中讀取數(shù)據(jù)生成 Managed Object,或保存 Managed Object 寫入數(shù)據(jù)文件啦租。
- NSManagedObjectContext 參與對(duì)數(shù)據(jù)進(jìn)行各種操作的整個(gè)過程哗伯,它持有 Managed Object。我們通過它來(lái)監(jiān)測(cè) Managed Object篷角。監(jiān)測(cè)數(shù)據(jù)對(duì)象有兩個(gè)作用:支持 undo/redo 以及數(shù)據(jù)綁定焊刹。這個(gè)類是最常被用到的。
- Array Controller, Object Controller, Tree Controller 這些控制器一般與 NSManagedObjectContext 關(guān)聯(lián)恳蹲,因此我們可以通過它們?cè)?nib 中可視化地操作數(shù)據(jù)對(duì)象虐块。