一、什么是數據持久化
數據持久化及數據的永久存儲,將數據保存在硬盤中,程序關閉,內存釋放后,重新打開程序,可以繼續訪問之前保存的數據。
二、數據持久化方式
常見的數據持久化方式有以下幾項:
沙盒
PReference
歸檔 / 反歸檔
SQLite
CoreData
這篇只講沙盒,preference,歸檔/反歸檔。
1.沙盒
沙盒是系統為每一個應用程序生成的一個特定文件夾 文件夾的名字由十六進制數據組成,每一個應用程序的沙盒文件名都是不一樣的,是由系統隨機生成的。
//獲取沙盒主目錄 NSString *path = NSHomeDirectory(); NSLog(@"%@",path);
沙盒下每個文件夾的路徑及作用
//Documents 存放的一些比較重要的文件,但是存入Documents中的文件不能過大 //如何獲取Documents文件目錄 NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSLog(@"%@",documentsPath); //用firstobject取值是因為該方法一開始使用mac端OS X開發,對于PC端用戶可以有多個用戶,所以可以取到很多user的路徑,但是該方法現在用于手機開發,手機端只有一個用戶,所以獲得的用戶只有一個,lastobject也是可以的。 //Library:是一個資源庫,存儲一些不太重要的數據,相對比較大一些,里邊有兩個子文件夾; NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)firstObject]; //Caches:緩存文件,圖片緩存,音頻,視頻。網頁資源。應用程序清除緩存,就是清除該文件夾 NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject]; //Preferences:系統偏好設置,用戶對應程序的設置,比如用戶名和用戶密碼,preference路徑無法找到,通過NSUserDefaults //temp:存放臨時文件,比如下載的壓縮包zip,解壓后理解把壓縮包刪除 NSString *tempPath = NSTemporaryDirectory(); NSLog(@"%@",tempPath); //bundle:ios8之前,包和沙河在同一個目錄下,之后.app單獨存儲到一個獨立的文件目錄下。 .app 文件 readOnly。從appStore下載下來的是這個包,程序上傳的時候也是這個包 NSString *bundlepath = [[NSBundle mainBundle] bundlePath]; NSLog(@"%@",bundlepath);
// NSSearchPathDirectory 這個類是用來查找文件目錄的 //第一個參數:文件名稱 //第二個參數,確定搜索域 //第三個參數:確定相對路徑還是絕對路徑。YES絕對,NO相對
文件相關操作
/** * 文件刪除 */- (void)deleteFile { NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; NSString *imagePath = [cachesPath stringByAppendingPathComponent:@"iamge"]; NSLog(@"%@",imagePath); //創建文件管理者 NSFileManager *fileManager = [NSFileManager defaultManager]; //判斷文件是否存在 BOOL isExist = [fileManager fileExistsAtPath:imagePath]; if (!isExist) { BOOL isSuccess = [fileManager createDirectoryAtPath:imagePath withIntermediateDirectories:YES attributes:nil error:nil]; NSLog(@"%@",isSuccess ? @"創建成功" : @"創建失敗"); } //刪除文件 if ([fileManager fileExistsAtPath:imagePath]) { BOOL isSucess = [fileManager removeItemAtPath:imagePath error:nil]; NSLog(@"%@",isSucess ? @"刪除成功" : @"刪除失敗"); }}
/** * 移動 */- (void)moveFile { NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; NSString *imagePath = [cachesPath stringByAppendingPathComponent:@"iamge"]; NSLog(@"%@",imagePath); //創建文件管理者 NSFileManager *fileManager = [NSFileManager defaultManager]; //判斷文件是否存在 BOOL isExist = [fileManager fileExistsAtPath:imagePath]; if (!isExist) { BOOL isSuccess = [fileManager createDirectoryAtPath:imagePath withIntermediateDirectories:YES attributes:nil error:nil]; NSLog(@"%@",isSuccess ? @"創建成功" : @"創建失敗"); } //刪除文件 // if ([fileManager fileExistsAtPath:imagePath]) { // BOOL isSucess = [fileManager removeItemAtPath:imagePath error:nil]; // NSLog(@"%@",isSucess ? @"刪除成功" : @"刪除失敗"); // } //拷貝文件 // 把包中的plist文件拷貝到image文件夾下 NSString *plistInBundlePath = [[NSBundle mainBundle] pathForResource:@"NB.plist" ofType:nil]; NSString *nBPath = [imagePath stringByAppendingPathComponent:@"NB.plist"]; // 拷貝, if (![fileManager fileExistsAtPath:nBPath]) { BOOL isSuccess = [fileManager copyItemAtPath:plistInBundlePath toPath:nBPath error:nil]; NSLog(@"%@",isSuccess ? @"拷貝成功" : @"拷貝失敗"); } NSString *toPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject]; BOOL isSuccess = [fileManager moveItemAtPath:nBPath toPath:[toPath stringByAppendingPathComponent:@"NB.plist"] error:nil]; NSLog(@"%@",isSuccess ? @"移動成功" : @"移動失敗"); }
//字符串寫入文件- (void)writeToFile { //簡單對象寫入文件:字符串,數組,字典,二進制流 只有這些簡單對象支持文件的寫入 //如果要寫入的文件數據時數組,字典,必須要保證數組,字典中的數據 也是簡單對象(如果是復雜對象,請參照后邊的歸檔,反歸檔) //將字符串寫入Documents文件夾下 NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject]; NSString *toPath = [documentsPath stringByAppendingPathComponent:@"string.txt"]; NSString *string = @"string-string-string-"; //第一個參數,要寫入的文件路徑,如果不存在文件,會自動創建 第二個參數,原子性,判斷是否需要生成輔助文件,保護在多線程下安全 第三個參數,編碼格式 第四個參數,錯誤信息 NSError *error = nil; BOOL isSuccess = [string writeToFile:toPath atomically:YES encoding:NSUTF8StringEncoding error:&error]; NSLog(@"%@",isSuccess ? @"寫入成功" : @"寫入失敗"); NSString *str = [NSString stringWithContentsOfFile:toPath encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@",str);}
//數組寫入文件- (void)writeArray { NSString *str = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)firstObject]; NSString *toPath = [str stringByAppendingPathComponent:@"array.txt"]; NSArray *array = @[@"123",@"123"]; BOOL isSuccess = [array writeToFile:toPath atomically:YES]; NSLog(@"%@",isSuccess ? @"寫入成功" : @"寫入失敗"); NSArray *arr = [NSArray arrayWithContentsOfFile:toPath]; NSLog(@"%@",arr);}
//字典寫入文件- (void)writeDic { NSDictionary *dic = @{@"key":@"value"}; NSString *str = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject]; NSString *toPath = [str stringByAppendingPathComponent:@"dictonry.txt"]; BOOL isSuccess = [dic writeToFile:toPath atomically:YES]; NSLog(@"%@",isSuccess ? @"成功" : @"失敗"); NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:toPath]; NSLog(@"%@",dict);}
//NSData寫入文件- (void)writeData { NSString *tempPath = NSTemporaryDirectory(); NSString *toPath = [tempPath stringByAppendingPathComponent:@"data.txt"]; NSString *string = @"datadata"; NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; BOOL isSuccess = [data writeToFile:toPath atomically:YES]; NSLog(@"%@",isSuccess ? @"成功" : @"失敗"); NSData *getData = [NSData dataWithContentsOfFile:toPath]; NSString *str = [[NSString alloc] initWithData:getData encoding:NSUTF8StringEncoding]; NSLog(@"%@",str);}
2.preference
//Preference- (void)writeToPreference { // NSUserDefaults 繼承自NSObject ,單例 通過kvc模式賦值 NSLog(@"%@",NSHomeDirectory()); //創建用戶索引對象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setInteger:100 forKey:@"money"]; //立即同步操作 對preference中的文件進行修改后,立即同步 [defaults synchronize]; NSInteger money = [defaults integerForKey:@"money"]; NSLog(@"%ld",money); [defaults setInteger:10000 forKey:@"MyMoney"]; [defaults synchronize]; NSInteger you = [defaults integerForKey:@"you"]; NSLog(@"%ld",(long)you); if (money < 10) { NSLog(@"there is no money"); } else { NSLog(@"-100"); money -= 100; [defaults setInteger:40 forKey:@"money"]; [defaults setInteger:1000 forKey:@"YourMoney"]; } // NSUserDefaults 一般存儲一些比較小的數據,大部分用來存數值 //例子:判斷用戶是否第一次登陸 NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; BOOL isFirst = [userDefault boolForKey:@"isFirst"]; [userDefault setBool:YES forKey:@"isFirst"]; [userDefault synchronize]; if (!isFirst) { NSLog(@"第一次登陸"); } else { NSLog(@"不是第一次登陸"); }}
3.歸檔 / 反歸檔
復雜對象寫入文件需要使用歸檔 ,讀取需要使用反歸檔,不能直接寫入文件,數組中有復雜對象也要使用歸檔 / 反歸檔
復雜對象使用行歸檔和反歸檔,需要遵循NSCoding協議,并實現協議中- (void)encodeWithCoder:(NSCoder *)aCoder; - (id)initWithCoder:(NSCoder *)aDecoder; 兩個方法
新建Person類
在Person.h中 遵循協議
//// Person.h// 07.24-DataPersistiser//// Created by lanouhn on 14/7/24.// Copyright (c) 2014年 LCD. All rights reserved.//#import <Foundation/Foundation.h>@interface Person : NSObject <NSCoding>@property (nonatomic, copy) NSString *name;@property (nonatomic, copy) NSString *gender;@property (nonatomic, assign) NSInteger age;@end
在Person.m中實現協議方法
//// Person.m// 07.24-DataPersistiser//// Created by lanouhn on 14/7/24.// Copyright (c) 2014年 LCD. All rights reserved.//#import "Person.h"@implementation Person//當要歸檔時,對象會自動觸發這個方法- (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.name forKey:@"name"]; [aCoder encodeObject:self.gender forKey:@"gender"]; [aCoder encodeObject:@(self.age) forKey:@"age"];}- (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; if (self) { self.name = [aDecoder decodeObjectForKey:@"name"]; self.gender = [aDecoder decodeObjectForKey:@"gender"]; self.age = [[aDecoder decodeObjectForKey:@"age"] integerValue]; } return self;}@end
歸檔 / 反歸檔
- (void)archiver { //把復雜文件寫入文件,先轉化為nsdata對象 //歸檔:歸檔的實質就是把其他類型的數據(person),先轉化為NSData,再寫入文件。 Person *person = [[Person alloc] initWithName:@"rose" gender:@"girl" age:25]; // NSKeyedArchiver 壓縮工具類,繼承自NSCoder,主要用于編碼 NSMutableData *data = [NSMutableData data] ; NSKeyedArchiver *achiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //使用壓縮工具講Person壓到data中 [achiver encodeObject:person forKey:@"person"]; //完成壓縮,停掉壓縮工具 [achiver finishEncoding]; NSString *homePath = NSHomeDirectory(); NSString *toPath = [homePath stringByAppendingPathComponent:@"person.txt"]; BOOL isSuccess = [data writeToFile:toPath atomically:YES]; NSLog(@"%@",isSuccess ? @"成功" : @"失敗"); //復雜對象的讀取,反歸檔 // NSKeyedUnarchiver NSData *getData = [NSData dataWithContentsOfFile:toPath]; NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:getData]; //解壓 Person *p1 = [unArchiver decodeObjectForKey:@"person"]; [unArchiver finishDecoding];}
//集合NSArray NSDictionary 如果想進行歸檔和反歸檔,那么它里邊存儲的元素也要遵循NSCoding協議 Person *person1 = [[Person alloc] initWithName:@"jack" gender:@"男" age:20]; Person *person2 = [[Person alloc] initWithName:@"rose" gender:@"女" age:20]; NSArray *array = @[person1,person2]; NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; [archiver encodeObject:array forKey:@"array"]; [archiver finishEncoding]; NSString *tmpPath = NSTemporaryDirectory(); NSString *toPath = [tmpPath stringByAppendingString:@"array.txt"]; BOOL isSuccess = [data writeToFile:toPath atomically:YES]; NSLog(@"%@",isSuccess ? @"成功" : @"失敗"); //反歸檔 NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; NSArray *unArchiverArray = [unArchiver decodeObjectForKey:@"array"];
新聞熱點
疑難解答