我們知道儲存方式分為兩種:內存 和 閃存。內存的存儲是臨時的,運行時是有效的且效率很高,而閃存則是一種持久化儲存,但產生I/O消耗,效率相對低。我們把內存中的數據轉移到閃存中進行持久化的操作叫做歸檔。
然而兩者結合起來就是我們常用的數據存儲方法。通常我們所用到的:CoreData、SQLite、NSUserDefaults等都是數據存儲的方法。
- plist NSArray/NSDictionary
- NSCoding 歸檔反歸檔
- NSUserDefaults用于存儲配置信息
- SQLite用于存儲查詢需求較多的數據
- CoreData用于規劃應用中的對象
輕量級本地數據存儲
NSUserDefaults單例以key-value的形式存儲了一系列偏好設置,key是名稱,value是相應的數據。存/取數據時可以使用方法objectForKey:和setObject:forKey:來把對象存儲到相應的plist文件中,或者讀取,既然是plist文件,那么對象的類型則必須是plist文件可以存儲的類型:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.而如果需要存儲plist文件不支持的類型,比如圖片,可以先將其歸檔為NSData類型,再存入plist文件.
- 對相同的Key賦值約等于一次覆蓋,要保證每一個Key的唯一性
- NSUserDefaults 存儲的對象全是不可變的
保存在NSUserDefaults中的信息在你的應用關閉后再次打開之后依然存在。保存信息到NSUserDefaults的一個例子就是保存用戶是否已登錄的狀態。我們把用戶的登錄狀態保存到NSUserDefaults以便用戶關閉應用再次打開應用的時候,應用能夠從NSUserDefaults獲取數據,根據用戶是否登錄展示不同的界面。有些應用也用這個功能來保存機密數據,比如用戶的訪問令牌,以便下次應用登錄的時候,它們能夠使用這個令牌來再次認證用戶。但是保存到NSUserDefaults的數據并沒有加密,因此可以很容易的從應用的包中看到。NSUserDefaults被存在一個以應用的bundle id為名稱的plist文件中。
存儲:
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *string = @"hahaha";
[user setObject:string forKey:@"myKey"];
[user synchronize];//寫完別忘了同步
讀取:
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSString *value = [user objectForKey:@"myKey"];
SQLite
然而我們面對大量數據寫入的時候 輕量級儲存明顯不適用。SQLite的優點就是他占用資源非常低,處理速度快。
SQLite是如何存儲的?
數據庫的存儲就像平時我們用的excel表格,它也是以表為單位。橫縱分別對應屬性名和自己的ID。
- 新建一個數據庫
- 新建一張表(table)
- 添加多個字段(column,列,屬性)
- 添加多行記錄(row,每行存放多個字段對應的值 三、SQL語句種類
- 數據定義語句(DDL:Data Definition Language) 包括create和drop等操作 在數據庫中創建新表或刪除表(create table或 drop table)
- 數據操作語句(DML:Data Manipulation Language) 包括insert、update、delete等操作 上面的3種操作分別用于添加、修改、刪除表中的數據
- 數據查詢語句(DQL:Data Query Language) 可以用于查詢獲得表中的數據 關鍵字select是DQL(也是所有SQL)用得最多的操作 其他DQL常用的關鍵字有where,order by,group by和having
libsqlite3.dylib與libsqlite3.0.dylib是不同的,libsqlite3.dylib是一個指向libsqlite3.0.dylib的索引,而且總是指向最新的sqlite3動態庫。(如果有新的libsqlite3.1.dylib出現則會指向3.1)
/**
* 單例方法實現
*
*/
+(instancetype)sharedDataBase {
static RYBaseHandle *baseHandle = nil;
if (baseHandle == nil) {
baseHandle = [[RYBaseHandle alloc] init];
}
return baseHandle;
}
/**
* 定義sqlite實例
*/
static sqlite3 *sqlite;
/**
* 打開數據庫
*/
-(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 {
}
}
/**
* 創建表格
*/
-(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 {
}
}
以及增刪改查等語句:
更新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 {
}
查詢 [返回數組]:
/**
* 創建數據庫跟隨指針,用來循環遍歷表格中的每一行
*/
NSString *selectSql = @"select * from collect";
sqlite3_stmt *stmt = nil;
/**
* 數據庫內查詢
*
* @param sqlite 數據庫名稱
* @param selectSql.UTF8String 查詢
* @param -1 字數限制 [-1 表示不限制]
* @param stmt 跟隨指針對象查詢
* @param nil ???
*
* @return 查詢結果
*/
int result = sqlite3_prepare_v2(sqlite, selectSql.UTF8String, -1, &stmt, nil);
/**
初始化返回數組
- returns: 可變數組
*/
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];
/**
* 將找到的數據放入數組中返回
*/
[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;
}
刪除:
/**
* 創建刪除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 {
}
關閉數據庫:
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用起來太過于麻煩,有些固定的語句特別容易出錯,這也就是為什么蘋果鼓勵用CoreData。CoreData優點:能夠合理管理內存,避免使用sql的麻煩,高效.
構成:
- Managed Object Model:是描述應用程序的數據模型,這個模型包含實體(Entity),特性(Property),讀取請求(Fetch Request)。
- Managed Object Context:參與對數據對象進行各種操作的全過程,并監測數據對象的變化,以提供對 undo/redo 的支持及更新綁定到數據的 UI。
- Persistent Store Coordinator 相當于數據文件管理器,處理底層的對數據文件的讀取與寫入。
- Managed Object 數據對象,與 Managed Object Context 相關聯。
- 圖中綠色的 Array Controller, Object Controller, Tree Controller 這些控制器,一般都是通過 control+drag 將 Managed Object Context 綁定到它們,這樣我們就可以在 nib 中可視化地操作數據。
具體步驟:
- 應用程序先創建或讀取模型文件(后綴為xcdatamodeld)生成 NSManagedObjectModel 對象。Document應用程序是一般是通過 NSDocument 或其子類 NSPersistentDocument)從模型文件(后綴為 xcdatamodeld)讀取。
- 然后生成 NSManagedObjectContext 和 NSPersistentStoreCoordinator 對象,前者對用戶透明地調用后者對數據文件進行讀寫。
- NSPersistentStoreCoordinator 負責從數據文件(xml, sqlite,二進制文件等)中讀取數據生成 Managed Object,或保存 Managed Object 寫入數據文件。
- NSManagedObjectContext 參與對數據進行各種操作的整個過程,它持有 Managed Object。我們通過它來監測 Managed Object。監測數據對象有兩個作用:支持 undo/redo 以及數據綁定。這個類是最常被用到的。
- Array Controller, Object Controller, Tree Controller 這些控制器一般與 NSManagedObjectContext 關聯,因此我們可以通過它們在 nib 中可視化地操作數據對象。
CoreData相關1
CoreData相關2
未完...