存儲(chǔ)位置
沙盒SandBox
app安裝后,系統(tǒng)會(huì)為其創(chuàng)建一個(gè)根目錄,用來(lái)寫(xiě)入應(yīng)用的數(shù)據(jù)或者首選項(xiàng)參數(shù),這個(gè)根目錄就是應(yīng)用程序的沙盒.
獲取沙盒目錄
NSString *homeDirectory = NSHomeDirectory();
或者
NSString *userName = NSUserName();
NSString * homeDirectory = NSHomeDirectoryForUser(userName);
結(jié)果是一樣的
/var/mobile/Containers/Data/Application/BD2819B1-5873-4A4F-8375-EE0CA8E6YFHG
沙盒下子目錄
AppName.app
存放應(yīng)用程序自身
Documents
存放用戶(hù)文檔和應(yīng)用數(shù)據(jù)文件(自動(dòng)備份)
獲取目錄
NSString *dpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Library
應(yīng)用程序規(guī)范的頂級(jí)目錄,下面有一些規(guī)范定義的的子目錄,當(dāng)然也可以自定義子目錄,用于存放應(yīng)用的文件,但是不宜存放用戶(hù)數(shù)據(jù)文件,和document一樣會(huì)被itunes同步,但不包括caches子目錄.
Library/Preferences:這里存放程序規(guī)范要求的首選項(xiàng)文件,包含應(yīng)用程序的偏好設(shè)置文件.您不應(yīng)該直接創(chuàng)建偏好設(shè)置文件,而是應(yīng)該使用NSUserDefaults類(lèi)來(lái)取得和設(shè)置應(yīng)用程序的偏好.(自動(dòng)備份)
獲取Library目錄:
NSString *lpath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Library/Caches:保存應(yīng)用的持久化數(shù)據(jù),用于應(yīng)用升級(jí)或者應(yīng)用關(guān)閉后的數(shù)據(jù)保存,不會(huì)被itunes同步,所以為了減少同步的時(shí)間,可以考慮將一些比較大的文件而又不需要備份的文件放到這個(gè)目錄下(不刪除,不備份)
獲取Library/Caches目錄:
NSString *cpath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
Tmp
存放臨時(shí)文件,在應(yīng)用關(guān)閉后,該目錄下的數(shù)據(jù)將刪除,也可能系統(tǒng)在程序不運(yùn)行的時(shí)候清除.(隨時(shí)刪除)
NSString *tpath = NSTemporaryDirectory();
PS: --------------------------------------
NSSearchPathForDirectoriesInDomains路徑獲取函數(shù)詳解:
FOUNDATION_EXPORT NSArray *NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory directory,
NSSearchPathDomainMask domainMask,
BOOL expandTilde);
該方法用于返回指定范圍內(nèi)的指定名稱(chēng)的目錄的路徑集合。有三個(gè)參數(shù):
directory:是NSSearchPathDirectory類(lèi)型的enum值,表明我們要搜索的目錄名稱(chēng),比如這里用NSDocumentDirectory表明我們要搜索的是Documents目錄.如果我們將其換成NSCachesDirectory就表示我們搜索的是Library/Caches目錄.
typedef NS_ENUM(NSUInteger, NSSearchPathDirectory) {
NSApplicationDirectory = 1, // supported applications (Applications)
NSDemoApplicationDirectory, // unsupported applications, demonstration versions (Demos)
NSDeveloperApplicationDirectory, // developer applications (Developer/Applications). DEPRECATED - there is no one single Developer directory.
NSAdminApplicationDirectory, // system and network administration applications (Administration)
NSLibraryDirectory, // various documentation, support, and configuration files, resources (Library)
NSDeveloperDirectory, // developer resources (Developer) DEPRECATED - there is no one single Developer directory.
NSUserDirectory, // user home directories (Users)
NSDocumentationDirectory, // documentation (Documentation)
NSDocumentDirectory, // documents (Documents)
NSCoreServiceDirectory, // location of CoreServices directory (System/Library/CoreServices)
NSAutosavedInformationDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 11, // location of autosaved documents (Documents/Autosaved)
NSDesktopDirectory = 12, // location of user's desktop
NSCachesDirectory = 13, // location of discardable cache files (Library/Caches)
NSApplicationSupportDirectory = 14, // location of application support files (plug-ins, etc) (Library/Application Support)
NSDownloadsDirectory NS_ENUM_AVAILABLE(10_5, 2_0) = 15, // location of the user's "Downloads" directory
NSInputMethodsDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 16, // input methods (Library/Input Methods)
NSMoviesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 17, // location of user's Movies directory (~/Movies)
NSMusicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 18, // location of user's Music directory (~/Music)
NSPicturesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 19, // location of user's Pictures directory (~/Pictures)
NSPrinterDescriptionDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 20, // location of system's PPDs directory (Library/Printers/PPDs)
NSSharedPublicDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 21, // location of user's Public sharing directory (~/Public)
NSPreferencePanesDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 22, // location of the PreferencePanes directory for use with System Preferences (Library/PreferencePanes)
NSApplicationScriptsDirectory NS_ENUM_AVAILABLE(10_8, NA) = 23, // location of the user scripts folder for the calling application (~/Library/Application Scripts/code-signing-id)
NSItemReplacementDirectory NS_ENUM_AVAILABLE(10_6, 4_0) = 99, // For use with NSFileManager's URLForDirectory:inDomain:appropriateForURL:create:error:
NSAllApplicationsDirectory = 100, // all directories where applications can occur
NSAllLibrariesDirectory = 101, // all directories where resources can occur
NSTrashDirectory NS_ENUM_AVAILABLE(10_8, NA) = 102 // location of Trash directory
};
其中:
NSDocumentDirectory是指程序中對(duì)應(yīng)的Documents路徑。
NSDocumentionDirectory對(duì)應(yīng)于程序中的Library/Documentation路徑,這個(gè)路徑是沒(méi)有讀寫(xiě)權(quán)限的,所以看不到文件生成。
** domain:**是MaskNSSearchPathDomainMask類(lèi)型的enum值,指定搜索范圍,這里的NSUserDomainMask表示搜索的范圍限制于當(dāng)前應(yīng)用的沙盒目錄.還可以寫(xiě)成NSLocalDomainMask(表示/Library)、NSNetworkDomainMask(表示/Network)等.
typedef NS_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
NSUserDomainMask = 1, // user's home directory --- place to install user's personal items (~)
NSLocalDomainMask = 2, // local to the current machine --- place to install items available to everyone on this machine (/Library)
NSNetworkDomainMask = 4, // publically available location in the local area network --- place to install items available on the network (/Network)
NSSystemDomainMask = 8, // provided by Apple, unmodifiable (/System)
NSAllDomainsMask = 0x0ffff // all domains: all of the above and future items
};
expandTilde:是BOOL值,表示是否展開(kāi)波浪線。我們知道在iOS中的全寫(xiě)形式是/User/userName,該值為YES即表示寫(xiě)成全寫(xiě)形式,為NO就表示直接寫(xiě)成“~”。
資源目錄
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:filename];
NSString *path = [[NSBundle mainBundle] resourcePath];
NSString *path = [[NSBundle mainBundle] pathForResource: @"info" ofType: @"txt"];
存儲(chǔ)方法
1.NSKeyedArchiver
歸檔保存數(shù)據(jù),該數(shù)據(jù)對(duì)象需要遵守NSCoding協(xié)議,并且該對(duì)象對(duì)應(yīng)的類(lèi)必須提供encodeWithCoder:和initWithCoder:方法。前?個(gè)方法告訴系統(tǒng)怎么將對(duì)象編碼,而后?個(gè)方法是告訴系統(tǒng)怎么將對(duì)象解碼。
//例如對(duì)Possession對(duì)象歸檔保存。
//定義Possession:
@interface Possession:NSObject //遵守NSCoding協(xié)議
{
NSString *name;//待歸檔類(lèi)型
}
@implementation Possession
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:name forKey:@"name"];
}
-(void)initWithCoder:(NSCoder *)aDecoder{
name=[[aDeCoder decodeObjectforKey:@"name"] retain];
}
歸檔操作:
如果對(duì)Possession對(duì)象allPossession歸檔保存,只需使用NSCoder子類(lèi)NSKeyedArchiver的方法 archiveRootObject:toFile:,返回值flag為YES表示序列化成功反之失敗。
NSString *path = [self possessionArchivePath]; BOOL flag = [NSKeyedArchiver archiveRootObject:allPossessions toFile: path ];
解壓操作:
同樣調(diào)用NSCoder子類(lèi)NSKeyedArchiver的方法unarchiveRootObject:toFile:即可。
allPossessions = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain];
缺點(diǎn):歸檔的形式來(lái)保存數(shù)據(jù),只能一次性歸檔保存以及?次性解壓。所以只能針對(duì)小量數(shù)據(jù),而且對(duì)數(shù)據(jù)操作比較 笨拙,即如果想改動(dòng)數(shù)據(jù)的某一小部分,還是需要解壓整個(gè)數(shù)據(jù)或者歸檔整個(gè)數(shù)據(jù)。
補(bǔ)充:關(guān)于結(jié)構(gòu)體的序列化
2.NSUserDefaults
NSUserDefaults是單例,同時(shí)也是線程安全的,操作方法幾乎與NSDictionary的操作方法無(wú)異, 用來(lái)保存應(yīng)用程序設(shè)置和屬性、用戶(hù)保存的數(shù)據(jù)。
用戶(hù)再次打開(kāi)程序或開(kāi)機(jī)后這些數(shù)據(jù)仍然存在,數(shù)據(jù)以plist格式歸檔在相應(yīng)應(yīng)用目錄的Library/Preferences下。
NSUserDefaults會(huì)把全部的數(shù)據(jù)都載入到內(nèi)存,而且之后常駐內(nèi)存,所以操作速度很快,但大規(guī)模數(shù)據(jù)不適合用NSUserDefaults。
NSUserDefaults可以存儲(chǔ)的數(shù)據(jù)類(lèi)型包括:
NSData、NSString、NSNumber、NSDate、NSArray、 NSDictionary。
如果要存儲(chǔ)其他類(lèi)型,則需要轉(zhuǎn)換為前面的類(lèi)型,才能用NSUserDefaults存儲(chǔ)。
實(shí)例1.簡(jiǎn)單的存取NSString 、NSData
//保存NSString 、NSData
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
NSString *name =@"xiao ming";
[defaults setObject:name forKey:@"name"];
UIImage *image=[[UIImage alloc]initWithContentsOfFile:@"photo.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 100);
[defaults setObject:imageData forKey:@"image"];
//這句不寫(xiě)的話也會(huì)自動(dòng)執(zhí)行
[defaults synchronize];
//讀取NSString 、NSData
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
//根據(jù)鍵值取出name
NSString *name = [defaults objectForKey:@"name"];
NSData *imageData = [defaults dataForKey:@"image"];
//NSData轉(zhuǎn)換為UIImage
UIImage *Image = [UIImage imageWithData:imageData];
實(shí)例2.將自定義類(lèi)型數(shù)據(jù)存入NSUserDefaults 中
1.存儲(chǔ)全班同學(xué)的信息
我們可以建一個(gè)NSMutableArray* studentArr來(lái)存放全班同學(xué)的信息(里面存儲(chǔ)的全是模型Student對(duì)象).
需要存儲(chǔ)的時(shí)候可以建一個(gè)NSMutableArray * dataArray把每一個(gè)模型專(zhuān)轉(zhuǎn)成data 添加到數(shù)組,然后存入NSUserDefaults。
//首先,要建立一個(gè)可變數(shù)組來(lái)存儲(chǔ) NSData對(duì)象
Student *student = [[Student alloc] ini];
//下面進(jìn)行的是對(duì)student對(duì)象的 name , studentNumber ,sex 的賦值
student.name = @"lady-奕奕";
student.studentNumber = @"3100104006";
student.sex = @"女";
//這是一個(gè)存放全班同學(xué)的數(shù)組
NSMutableArray * dataArray = [NSMutableArray arrayWithCapacity:50];
//將student類(lèi)型變?yōu)镹SData類(lèi)型
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
//存放數(shù)據(jù)的數(shù)組將data加入進(jìn)去
[dataArray addObject:data];
//存一個(gè)人的信息,直接將NSData存入NSUserDefaults中 :
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:data forKey:@"oneStudent"];
//存儲(chǔ)全班同學(xué)的信息,用一個(gè)for循環(huán)將data 放入 dataArray中:
for (Student *student in studentArr){
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
[dataArray addObject:data];
}
//記住要轉(zhuǎn)換成不可變數(shù)組類(lèi)型
NSArray * array = [NSArray arrayWithArray:dataArray];
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:array forKey:@"allStudent"];
2.從NSUserDefaults中取出數(shù)據(jù)在還原
//還原一個(gè)學(xué)生的數(shù)據(jù):
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSdData *data = [user objectForKey:@"oneStudent"];
Student *student = [NSKeyedUnarchiver unarchiveObjectWithData:data];
//還原全部學(xué)生數(shù)據(jù)
NSUserDefaults * user = [NSUserDefaults standardUserDefaults];
NSArray * array = [defaults objectForKey:@"allStudent"];
NSMutableArray *temArr = [[NSMutableArray alloc] init];
for (NSData * data in array){
[temArr addObject:[NSKeyedUnarchiver unarchiveObjectWithData: data]];
}
3. Write寫(xiě)入
永久保存在磁盤(pán)中。具體方法為:
第一步:獲得文件即將保存的路徑:
NSString *dpath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
還有一種方法是使用NSHomeDirectory函數(shù)獲得sandbox的路徑。具體的用法為:
NSString *sPath = NSHomeDirectory();
NSString *dpath = [sPath stringByAppendingPathComponent:@"Documents"];
兩者的區(qū)別:使用NSSearchPathForDirectoriesInDomains比在NSHomeDirectory后面添加Document更加安全。因?yàn)樵撐募夸浛赡茉谖磥?lái)發(fā)送的系統(tǒng)上發(fā)生改變。
第二步:生成在該路徑下的文件:
假如文件名叫:hahaha.plist
NSString *filename=[dpath stringByAppendingPathComponent:@"hahaha.plist"];
第三步:往文件中寫(xiě)入數(shù)據(jù):
//將NSData類(lèi)型對(duì)象data寫(xiě)入文件,文件名為filename
[data writeToFile: filename atomically:YES];
最后:從文件中讀出數(shù)據(jù):
NSData data=[NSData dataWithContentsOfFile: filename options:0 error:NULL];
4. SQLite
采用
SQLite數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù)。SQLite作為?一中小型數(shù)據(jù)庫(kù),應(yīng)用iOS中,跟前三種保存方式相比,相對(duì)復(fù)雜一些。
原生sqlite使用
- 需要添加SQLite相關(guān)的庫(kù)以及頭文件
在項(xiàng)目文件的Build Phases下,找到Link Binary Libraryies,
添加libsqlite3.0.dylib。
在項(xiàng)目文件中頭文件或者源文件中添加頭文件
#import "sqlite3.h"
關(guān)于libsqlite3.0.dylib和libsqlite3.dylib
libsqlite3.0.dylib本身是個(gè)鏈接,它指向libsqlite3.dylib。
在項(xiàng)目里添加libsqlite3.dylib或添加libsqlite3.0.dylib其實(shí)是添加了同一個(gè)文件。
libsqlite3.0.dylib總是指向最新的sqlite3動(dòng)態(tài)庫(kù)
比如說(shuō)sqlite3庫(kù)更新了,如果我們引用的是libsqlite3.0.dylib你就不需要做任何修改了。
- 開(kāi)始使用SQLite
使用前注意:如果不往數(shù)據(jù)庫(kù)里面添加任何的表,這個(gè)數(shù)據(jù)庫(kù)等于沒(méi)有建立,不會(huì)在硬盤(pán)上產(chǎn)生任何文件,如果數(shù)據(jù)庫(kù)已經(jīng)存在,則會(huì)打開(kāi)這個(gè)數(shù)據(jù)庫(kù)。
//dpath 是目錄里面講過(guò)的document 目錄
NSString *dbpath=[dpath stringByAppendingPathComponent:@"mydb"];
//打開(kāi)數(shù)據(jù)庫(kù)
if (sqlite3_open([dbpath UTF8String], &_db)==SQLITE_OK) {
NSLog(@"sqlite dadabase is opened.");
}else{ return;}//打開(kāi)不成功就返回
-(BOOL)openDB{
BOOL result = NO;
if (sqlite3_open([[self dbPath] UTF8String], &_db)==SQLITE_OK) {
result = YES;
NSLog(@"sqlite database is opended");
}else{
NSLog(@"sqlte database open faile");
result = NO;
}
return result;
}
建表:
char *error;
const char *createSql="CREATE TABLE IF NOT EXISTS table_name
(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)";
if (sqlite3_exec(_db, createSql, NULL, NULL, &error)==SQLITE_OK) {
NSLog(@"create table is ok.");
}else {
NSLog(@"error:%s",error);
sqlite3_free(error);//每次使用完畢清空error字符串,提供給下?一次使用
}
插入:
const char *insertSql="INSERT INTO table_name
('name','id') VALUES('WANGWU','210')";
if (sqlite3_exec(database, insertSql, NULL, NULL, &error)==SQLITE_OK) {
NSLog(@"insert operation is ok.");
}else {
NSLog(@"error: %s",error);
sqlite3_free(error);//每次使用完畢清空error字符串,提供給下?一次使用
}
查詢(xún):
const char *selectSql="select id,name from a person";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database,selectSql, -1, &statement, nil)==SQLITE_OK) {
NSLog(@"select operation is ok.");
}else {
sqlite3_free(error);
}
while(sqlite3_step(statement)==SQLITE_ROW) {
int _id=sqlite3_column_int(statement, 0);
NSString *name=(char*)sqlite3_column_text(statement, 1);
NSLog(@"row>>id %i, name %s",_id,name);
}
sqlite3_finalize(statement);
PS----------------------------------------
int sqlite3_prepare_v2(
//數(shù)據(jù)指針
sqlite3 *db,
//sql語(yǔ)句,使用UTF-8編碼
const char *zSql,
/*如果nByte小于0,則函數(shù)取出zSql中從開(kāi)始到第一個(gè)0終止符的內(nèi)容;
*如果nByte不是負(fù)的,那么它就是這個(gè)函數(shù)能從zSql中讀取的字節(jié)數(shù)的最大值。
*/
int nByte,
/*能夠使用sqlite3_step()執(zhí)行的 編譯好的 準(zhǔn)備語(yǔ)句的 指針
*如果錯(cuò)誤發(fā)生 它被置為NULL 如假如輸入的文本不包括sql語(yǔ)句。
*調(diào)用過(guò)程必須負(fù)責(zé)在編譯好的sql語(yǔ)句完成使用后使用sqlite3_finalize()刪除它。
*/
sqlite3_stmt **ppStmt,
/*zSql在遇見(jiàn)終止符或者是達(dá)到設(shè)定的nByte之后結(jié)束
假如zSql還有剩余的內(nèi)容 那么這些剩余的內(nèi)容被存放到pZTail中 不包括終止符
*/
const char **pzTail
);
說(shuō)明
如果執(zhí)行成功,則返回SQLITE_OK,否則返回一個(gè)錯(cuò)誤碼。
推薦在現(xiàn)在任何的程序中都使用sqlite3_prepare_v2這個(gè)函數(shù),
sqlite3_prepare只是用于前向兼容
最后,關(guān)閉數(shù)據(jù)庫(kù):
sqlite3_close(database);
注意:寫(xiě)入數(shù)據(jù)庫(kù),字符串可以采用char方式,而從數(shù)據(jù)庫(kù)中取出char類(lèi)型,當(dāng)char類(lèi)型有表示中文字符 時(shí),會(huì)出現(xiàn)亂碼。
這是因?yàn)閿?shù)據(jù)庫(kù)默認(rèn)使用ascII編碼方式。所以要想正確從數(shù)據(jù)庫(kù)中取出中文,需要用 NSString來(lái)接收從數(shù)據(jù)庫(kù)取出的字符串。
如果引入第三方庫(kù)會(huì)變得簡(jiǎn)單很多 比如FMDB。
讀取
1.讀取工程內(nèi)的JSON文件
<code>
NSString *path = [[NSBundle mainBundle] pathForResource:@"products.json" ofType:nil];// JSON文件的路徑
NSData *data = [NSData dataWithContentsOfFile:path]; // 加載JSON文件
NSArray *dictArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];// 將JSON數(shù)據(jù)轉(zhuǎn)為NSArray或者NSDictionary
</code>