IOS中資料的持久化儲存這塊内容,類似于Android中檔案的幾種常見的存儲方式。
對于資料的持久化存儲,ios中一般提供了4種不同的機制。
1.屬性清單
2.對象歸檔
3.資料庫存儲(SQLite3)
4.蘋果公司提供的持久性工具Core Data。
其實儲存的形式無非就這麼幾種,而我們還必須要關心的是,這些檔案會被放置在那個檔案下,然後如何讀取。
也就是說:IOS上資料存儲,我們要了解的兩點,資料存儲格式(也就是存儲機制),資料存儲位置。
1》檔案如何存儲(如上面4點)
2》檔案存儲在哪裡。
對于資料的操作,其實我們關心的是操作的速率。
就好比在Adnroid中偏好存儲,資料庫存儲,io存儲一樣。
我大緻問了我們公司新來的ios哥們,他說他們教育訓練機構基本對資料操作這塊就講了屬性清單和資料庫,以及普通的檔案存儲(比如音視訊圖這些多媒體資料)。
我就隻好先看看書了。
一:應用檔案目錄
首先我們來看了解下ios資料存儲位置,因為隻有知道位置路徑我們才能去讀取資料,而資料的持久化機制不過是針對操作速率來考慮的,
比如我們大緻知道屬性清單(既鍵值對形式)的存儲熟慮應該高于資料庫高于io檔案流存儲。
我們在選擇用何種機制存儲資料,主要也是看資料的形式。
一個ios應用安裝後大緻會有如下檔案夾及其對應路徑:

在mac上看模拟器中應用路徑:
/Users/nono/Library/Application Support/iPhone Simulator/5.1/Applications/2D135859-1E80-4754-B36D-34A53C521DE3
你在finder中的home下可能找不到Library這個目錄,因為貌似是影藏起來了(我這機器上是,在終端可以看到)。
最後那一竄的類似序列号的東西就是ios自動給應用生成的一組應用唯一識别碼最為了應用的home目錄名。
其下面就是上圖所示了。
書上對這些檔案夾介紹:
Document:應用程式将其資料存儲在這個檔案夾下,基于NSUserDefaults的首選項的設定除外。
簡單了解是,基本上我們要操作的一些資料都是存儲在這個檔案夾下面的
TIPS:這邊提下一點,對于ios系統這麼配置設定檔案夾,是因為在裝置進行同步時,ITunes有選擇性的意識來備份檔案。
比如我們可以猜到,tmp下的應該就不會備份了。
對于Document檔案夾目錄路徑的擷取,API提供了這麼一種方法:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths objectAtIndex:0];
Library:基于NSUserDefault首選項設定存儲在其下Preferences檔案夾中,簡單來說,這個檔案夾一般你很少操作到。
書上對于這部分基本沒介紹。估計對于初級部分是跳過了。
Tmp:應用臨時存儲檔案,當不需要時,應用負責删除其下的檔案資料。
該檔案也提供了目錄擷取方法:
NSString *tmpDoc = NSTemporaryDirectory();
應用程式檔案:這個基本沒提到書上,但是我們大緻可以猜測,這就是整個應用程式的程式檔案夾吧。
好了,以上我們大緻解決了我們提到的第一個點,檔案存儲目錄
二:資料存儲機制
1.屬性清單
這個其實我們早見過,plist就是,感覺用來存儲鍵值對小資料是最合适,因為速率很高。
這個存儲機制很簡單,對于前面我們使用過了在plist檔案來讀取資料填充一些清單,隻不過那會plist檔案存儲位置不同,
用的是Mainbundle什麼的來傳回檔案夾,其實這邊我也推測,上面提到有個應用程式檔案夾,它下面的檔案就是這麼來讀取的~(反正暫時不管他)
這邊不過就是改變了存儲位置,資料操作還是一樣的
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths objectAtIndex:0];
NSString *myFile = [docPath stringByAppendingPathComponent:@"my.list"];
//讀取檔案
NSArray *array = [[NSArray alloc] initWithContentsOfFile:myFile];
//操作完若修改了資料則,寫入檔案
[array writeToFile:myFile atomically:YES];
2.對象歸檔
上面的屬性清單存儲機制,我們都知道,這個機制支援NSArray,NSDictionary,NSData,NSString,NSNumber,NSDate 等等
這些對象直接寫入plist檔案中。
那麼對于一些複雜對象,我要儲存整個這個對象資料呢?
反正我是這麼覺得,這個機制很像java中的對象整體序列化。當然,這些資料在讀取是就需要遵循一種墨守成規的協定了。
首先我們定義的對象類,必須實作NSCoding和NSCopying協定(額,網上說後面這個不實作也可以,我猜是他對象沒有copy操作,是以沒出錯)書本上反正是實作了這兩個協定
然後歸檔中用到的操作類
NSKeyedArchiver
這邊我們定義一個對象,h檔案中定義兩屬性,申明要實作的NSCoding和NSCopying協定
實作檔案
//
// TestObj.m
// DataStorageTest
//
// Created by Nono on 12-5-12.
// Copyright (c) 2012年 NonoWithLilith. All rights reserved.
//
#import "TestObj.h"
@implementation TestObj
@synthesize stringA = stringA;
@synthesize stringB = stringB;
#pragma mark -
#pragma NSCoding協定實作實作
- (void)encodeWithCoder:(NSCoder *)aCoder
{ //encoder
[aCoder encodeObject:stringAforKey:@"1"];
[aCoder encodeObject:stringBforKey:@"2"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
//decoder
if (self = [superinit]) {
stringA = [[aDecoder decodeObjectForKey:@"1"] retain];
stringB = [[aDecoder decodeObjectForKey:@"2"] retain];
}
returnself;
}
#pragma NSCopying協定實作
- (id)copyWithZone:(NSZone *)zone
{
TestObj *copy = [[[selfclass] allocWithZone:zone] init];
copy.stringA = [[self.stringAcopyWithZone:zone] autorelease];
copy.stringB = [[self.stringBcopyWithZone:zone] autorelease];
return copy;
}
@end
然後是對對象歸檔的讀取和寫入
//讀取歸檔檔案
NSData *data = [[NSMutableDataalloc] initWithContentsOfFile:myFile];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiveralloc] initForReadingWithData:data];
TestObj * test = [unarchiver decodeObjectForKey:@"data"];
[unarchiver finishDecoding];
[data release];
[unarchiver release];
//寫入歸檔檔案
NSMutableData *data1 = [[NSMutableDataalloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiveralloc] initForWritingWithMutableData:data1];
[archiver encodeObject:test forKey:@"data"];
[archiver finishEncoding];
[data writeToFile:myFile atomically:YES];
[data1 release];
[archiver release];
[test release];
但是問了下新同僚,據說這個用到也是蠻少,至少他目前。
但是,我看了下,覺得這個和Android 中Parcelable
太尼瑪像似了
三.資料庫存儲
和Android一樣,ios中也是用了SQLite3這種嵌入式資料庫。
這個網上例子是很多了。我這邊就大緻看下了資料庫的打開,
資料庫表建立,查詢,插入
//資料庫操作
sqlite3 *database;
// const NSString * dbname = @"mydb"
int result;
//打開一個指定路徑的現有的資料庫,如果沒有則會建立一個db庫
result = sqlite3_open([myFile UTF8String], &database);
if (result != SQLITE_OK) {
sqlite3_close(database);
}
//建立一個db表
char *errorMsg;
NSString *sql_create_table = @"CREATE TABLE IF NOT EXISTS NONOTABLE 省略~~~~~~~~~~~~~";
int result1 ;
//sqlite_exec用了針對sqlite3運作任何不要傳回資料的指令,它用于執行更新,插入和删除。簡單來說,這個方法執行的都是一些無需傳回資料(雖然我們可能擷取一個狀态值。)。
result1 = sqlite3_exec(database, [sql_create_table UTF8String], NULL, NULL, &errorMsg);
//檢索查詢操作
int result2 ;
sqlite3_stmt *statment;
NSString *sql_selected = @"查詢語句";
result2 = sqlite3_prepare_v2(database, [sql_selected UTF8String], -1, &statment, nil);
if(result2 == SQLITE_OK){
//單步操作
while (sqlite3_step(statment) == SQLITE_ROW) {
int row = sqlite3_column_int(statment, 0);
char * rpwData = sqlite3_column_text(statment, 1);
}
sqlite3_finalize(statment);
}
//綁定變量,既就是插入操作的一種變種,比如我麼那上面提到sqlite_exec可以執行插入操作,插入内容直接是寫在sql字竄裡,但是考慮到字竄涉及到無效的符号以及會一些嚴重的注入漏洞(比如以前聽過的引号符号)。
NSString *sql_bind = @"insert into foo value(?,?)";
result2 = sqlite3_prepare_v2(database, [sql_selected UTF8String], -1, &statment, nil);
if(result2 == SQLITE_OK){
sqlite3_bind_int(statment, 1, 235);
sqlite3_bind_text(statment, 2, "test", -1, nil);
sqlite3_finalize(statment);
}
if (sqlite3_step(statment) != SQLITE_DONE)
NSLog(@"error");
sqlite3_finalize(statment);
sqlite3_close(database);
關于更多的,大夥可以自行百度,因為資料庫的操作文法太怪異了,書上說是基本是基于c的,本人沒學過c。看得有點心煩~
4。Core Data存儲機制
大緻浏覽下基本感覺就是将對象歸檔搞成了可視化和簡單化。
這塊内容比較多。網上資料也挺豐富的。
暫時不做介紹了。
總結下:其實對于ios資料存儲,最常用和主要要掌握的就是屬性清單和資料庫,因為兩個是出鏡率比較高的。
其他可能在資料存明顯展現出儲優勢時,我們會去考慮用另外兩種機制。
基礎的來說,必須掌握屬性清單和sqlite的操作存儲。