iOS中 資料持久化 UI進階_17
資料持久化的本質就是把資料由內寫到本地(硬碟中),在iOS指將資料寫到沙箱檔案夾下;
沙箱機制:指的就是採用沙箱檔案夾的形式管理應用程式的本地檔案,而且沙箱檔案夾的名字是隨機分配的,採用十六進位方法命名;
=======================關於沙箱目錄==========================
沙箱內部構造:
測試沙箱:
屬性:
@interface ViewController ()@property (retain, nonatomic) IBOutlet UITextField *nameField;@property (retain, nonatomic) IBOutlet UITextField *passwordField;@property(nonatomic,retain)NSUserDefaults *user;@end
//登入按鈕
- (IBAction)handleLgin:(UIButton *)sender { //取出輸入框中的資料 NSString *name = self.nameField.text; NSString *password = self.passwordField.text; //取出使用者喜好設定 NSString *pName = [self.user valueForKey:@name]; NSString *pPassword = [self.user valueForKey:@password]; //當輸入的內容和本機存放區的資訊相同時顯示登入成功 if ([name isEqualToString:pName] && [password isEqualToString:pPassword]) { NSLog(@登陸成功); }else{ NSLog(@登入失敗,請註冊); }}
//註冊按鈕
- (IBAction)handleRegister:(UIButton *)sender { NSString *name = self.nameField.text; NSString *password = self.passwordField.text; //當不輸入內容的時候提前結束方法 if (name.length == 0 || password.length == 0) { NSLog(@賬戶名或者密碼為空白,註冊失敗!); return; } //本地檔案中設定使用者名稱和使用者密碼 //設定使用者名稱 [self.user setObject:name forKey:@name]; //設定使用者密碼 [self.user setObject:password forKey:@password]; //同步資料 [self.user synchronize]; NSLog(@註冊成功); }
記得釋放:
- (void)dealloc { [_nameField release]; [_passwordField release]; self.user = nil; [super dealloc];}
測試結果:
————————————————————————
————————————————————————————
1.擷取沙箱檔案夾的路徑
NSHomeDirectory() 沙箱檔案的主目錄,在這個檔案夾下放著三個檔案Document,Libralay,Tmp,其中Library 中還有兩個檔案Caches,Perference,系統幫我們建立五個檔案存放在沙箱檔案下,這五個是不能刪除的
NSLog(@%@,NSHomeDirectory());
Documents: 存放一些比較重要的檔案,檔案大小比較小,這些都是可以有副本,此檔案夾中不能有太多東西,否則在上傳AppStore中會直接被拒,比如: 資料庫
擷取Documents 檔案夾的路徑
第一個參數:檔案夾的名字 64行
第二個參數:搜尋域,有優先順序:users -->local -->network -->system
第三個參數:相對路徑或者是絕對路徑 YES絕對路徑,NO代表相對路徑
此方法最早是應用在MAC端開發的,對於PC 端可以有很多的使用者,所以該方法的傳回值是一個數組,但是現在這個方法應用在移動端(iOS端),而移動端使用者只有一個,所以擷取的路徑也只有一個
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]; NSLog(@%@,documentsPath);
Library 資產庫,存放的一些不太重要的檔案,相對比較大,且其中有兩個子檔案
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)lastObject]; NSLog(@%@,libraryPath);
Caches 存放一些緩衝的檔案,如網頁緩衝,圖片緩衝,視頻緩衝,視頻緩衝,應用中清除緩衝功能,清理的就是這個檔案夾裡面的內容
//擷取Caches路徑
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject]; NSLog(@%@,cachesPath);
//Perferences 喜好設定,存放一些使用者的資訊
注意:路徑是找不到的,只能通過NSUserDefaults 訪問
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
//perferences 中存放的都是plist 檔案,在第一次設定索引值對的時候,會幫你建立plist檔案,如果直接取值的時候,plist 檔案是沒有的
賦值和取值:
// [user setBool:YES forKey:@login]; //取出BOOL值//BOOL isLogin = [user boolForKey:@login];// NSLog(@%d,isLogin);
//NSUserDefaults 支援的資料類型:array,dictionary,string,data,number,bool,integer等
//NSUserDefaults 中一般儲存數實值型別的資料,不存放大型的資料
//類比啟動使用者引導圖
BOOL isFirstLogin = [user boolForKey:@login]; if (NO == isFirstLogin) { NSLog(@第一次啟動); [user setBool:YES forKey:@login]; [user synchronize];//立即同步 }else{ NSLog(@不是第一次啟動); }
//Tem 存放臨時檔案 比如:壓縮包 zip ,解壓後就刪除處理了
擷取Tem的路徑
NSTemporaryDirectory(); NSLog(@%@,NSTemporaryDirectory()
NSFileManager 檔案管理類,是一個檔案管理工具,主要用於檔案的的添加、刪除、拷貝,繼承自 NSObject
NSFileManager 也是一個單例類
NSFileManager *fileManger = [NSFileManager defaultManager];
=======================檔案的建立==========================
NSFileManager常用操作一覽表:
//在Document 檔案下建立一個檔案 av.text
1.擷取Documents 路徑
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
2.建立av.text 的路徑
// stringByAppendingFormat 拼接上什麼就得到什麼// stringByAppendingString 拼接上什麼就得到什麼// stringByAppendingPathExtension 拼接的內容前加一個點// stringByAppendingPathComponent 拼接的內容前加一個 /
NSString *avPath = [documentsPath stringByAppendingPathComponent:@av]; NSLog(@%@,avPath);
首先判斷檔案是否存在
if ([fileManger fileExistsAtPath:avPath]) { NSLog(@存在); }else{ NSLog(@不存在); //建立 av.text檔案 //第二個參數詢問:如果路徑中沒有檔案夾是否自動建立 BOOL isSuccss = [fileManger createDirectoryAtPath:avPath withIntermediateDirectories:YES attributes:nil error:nil]; if (isSuccss) { NSLog(@建立成功); }else{ NSLog(@建立失敗); } }
=======================檔案的刪除==========================
//刪除檔案夾
1.先判斷有沒有要刪的檔案夾存在
if ([fileManger fileExistsAtPath:avPath]) { //如果存在就刪除 BOOL isSuccess = [fileManger removeItemAtPath:avPath error:nil]; NSLog(@%@,isSuccess ? @刪除成功:@刪除失敗); }
=======================檔案的拷貝==========================
//把NB.plist 拷貝到 AV 檔案夾下
//NSBundle 應用程式套件組合,我們從AppStore下載的應用就是這個包
//擷取應用程式套件組合的路徑
//iOS8.0 之後,**.app 單獨存放在一個檔案內,**.app 這個檔案只能讀,不能寫入,最終上傳到AppStore 的包就是這個包
NSString *bundlePath = [[NSBundle mainBundle]bundlePath]; NSLog(@%@,bundlePath);
//1.擷取NB.plist 的路徑 NSString *nbPath = [[NSBundle mainBundle]pathForResource:@NB.plist ofType:nil]; //2.製造移動到沙箱Documents 檔案夾下AV檔案夾下NB.plist NSString *desPath = [avPath stringByAppendingPathComponent:@NB.plist]; //3.檔案拷貝 if (![fileManger fileExistsAtPath:desPath]) { //第一個參數:copy之前的路徑 //第二個參數:要拷貝到的位置 BOOL isSucess = [fileManger copyItemAtPath:nbPath toPath:desPath error:nil]; NSLog(@%@,isSucess ? @拷貝成功:@拷貝失敗); }
=======================檔案的移動==========================
//從AV檔案夾下,移動到Library檔案夾下 //1.移動之前的路徑 NSString *surcePath = desPath; //2.移動之後的路徑 NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)lastObject]; NSString *toPath = [libraryPath stringByAppendingPathComponent:@NB.plist]; //移動 if (![fileManger fileExistsAtPath:toPath]) { BOOL isSuccess = [fileManger moveItemAtPath:surcePath toPath:toPath error:nil]; NSLog(@%@,isSuccess ? @移動成功:@移動失敗); } //調用簡單對象的寫入和讀取 [self simpleObjectWritwTpFileAndFromeFile]; //調用歸檔和反檔 [self archiverAndArchiver]; }
=======================簡單對象的寫入和讀取==========================
//簡單對象指的是:NSString ,NSDictionary,NSData以及他們的子類
//注意:集合(NSArray,NSDictionary)的元素,必須是上面的四種基礎資料型別 (Elementary Data Type),不能放複雜物件,才能直接進行檔案的寫入和讀取;
字串的寫入與讀取:
//1.字串的寫入 NSString *string = @小韓哥真帥; //2.在Documents 檔案夾下建立一個檔案text.text NSString *textPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@text.text];// NSLog(@%@,textPath); //3.字串的寫入 // 第一個參數:要寫入的檔案路徑 // 第二個參數: YES提供多線程的安全防護,NO則不提供安全防護 // 第三個參數:編碼的格式BOOL isSuccess = [string writeToFile:textPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; NSLog(@%@,isSuccess ? @寫入成功 :@寫入失敗); //4.字串從檔案中讀取資料 //第一個參數:要讀取的檔案路徑 NSString *contentString = [NSString stringWithContentsOfFile:textPath encoding:NSUTF8StringEncoding error:nil]; NSLog(@%@,contentString);
NSArray 的讀取和寫入:
//1.準備數組 NSArray *array = @[@小韓哥,@蔡國慶,@周杰倫]; //2.將數組寫入到 caches 檔案夾下 的array.text NSString *arrayPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@array.text]; //3.數組寫入 數組寫入後的檔案是XML格式的 isSuccess = [array writeToFile:arrayPath atomically:YES]; NSLog(@%@,isSuccess ? @數組寫入成功:@數組寫入失敗); //數組的讀取 NSArray *contentArray = [NSArray arrayWithContentsOfFile:arrayPath]; NSLog(@%@,contentArray);
NSDictionary 的寫入和讀取 寫入之後變成xml格式:
//1.準備字典 NSDictionary *dic = @{@男:@小韓哥,@明星:@蔡國慶,@國家主席:@習大大}; //2.tem 檔案夾下建立一個Dictionary.text 檔案 NSString *dictionaryPath = [NSTemporaryDirectory()stringByAppendingPathComponent:@dictionary.text]; //3.字典的寫入 isSuccess = [dic writeToFile:dictionaryPath atomically:YES]; NSLog(@%@,isSuccess ? @字典寫入成功:@字典寫入失敗); //4.字典的讀取 NSDictionary *contentDic = [NSDictionary dictionaryWithContentsOfFile:dictionaryPath]; NSLog(@%@,contentDic);
NSData 寫入和讀取:
NSString *dataString = @我想對我身邊人說,你該洗腳了; //1.準備NSData 對象 NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding]; //2.在library 中寫入 data.text 檔案 NSString *dataPath = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@data.text]; //3.NSData 的寫入 isSuccess = [data writeToFile:dataPath atomically:YES]; NSLog(@%@,isSuccess ? @NSData寫入成功:@NSData寫入失敗); //4.NSData 的讀取 NSData *contentData = [NSData dataWithContentsOfFile:dataPath]; //將二進位流轉為字串 NSString *newString = [[[NSString alloc]initWithData:contentData encoding:NSUTF8StringEncoding]autorelease]; NSLog(@%@,newString);
=======================複雜物件的寫入和讀取==========================
複雜物件,就是Fundation 架構下不存在的資料類,也就是我們自己定義類,就叫複雜物件,複雜物件不能直接寫入到檔案,必須藉助一些工具,NSKeyedArchiver(歸檔工具),讀取時必須藉助工具類NSKeyedUnarchiver(反歸檔工具)
歸檔和反檔:
1.建立複雜物件Person
Person.h
#import @interface Person : NSObject//如果複雜物件想要完成歸檔和反歸檔,則這個對象必須遵循NSCoding協議- (void)encodeWithCoder : (NSCoder *)aCoder;@property(nonatomic,copy)NSString *name;//姓名@property(nonatomic,copy)NSString *gender;//性別@property(nonatomic,assign)NSInteger age;//年齡- (id)initWithName : (NSString *)name gender : (NSString *)gender age : (NSInteger )age;@end
Person.m
#import Person.h@implementation Person- (void)dealloc{ self.name = nil; self.gender = nil; [super dealloc]; }- (id)initWithName : (NSString *)name gender : (NSString *)gender age : (NSInteger )age{ if (self = [super init]) { self.name = name; self.age = age; self.gender = gender; } return self;}-(NSString *)description{ return [NSString stringWithFormat:@%@-%@-%ld,_name,_gender,_age];}//歸檔的協議方法- (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{ if (self = [super init]) { //解碼 self.name = [aDecoder decodeObjectForKey:@name]; self.gender = [aDecoder decodeObjectForKey:@gender]; self.age = [[aDecoder decodeObjectForKey:@age]integerValue]; } return self;}@end
歸檔:
//1.建立複雜物件Person Person *p1 = [[[Person alloc]initWithName:@小韓哥 gender:@男 age:20]autorelease]; //2.建立歸檔工具 NSMutableData *data = [NSMutableData data]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data]; //3.歸檔 //第一個參數:要被歸檔的對象 //第二個參數:給歸檔對象一個key值,作為 標識,方便反歸檔的時候把它找回來 [archiver encodeObject:p1 forKey:@boyFriend]; //4.完成歸檔 [archiver finishEncoding]; //5.釋放 [archiver release]; //6.將歸檔後的資料檔案 //將檔案寫入到沙箱檔案夾下 NSString *personPath = [NSHomeDirectory() stringByAppendingPathComponent:@person.text]; //7.將轉化的data資料寫入到檔案中 BOOL isSuccess = [data writeToFile:personPath atomically:YES]; NSLog(@%@,isSuccess ? @寫入成功:@寫入失敗);
反歸檔:
NSData *contentData = [NSData dataWithContentsOfFile:personPath]; //1.建立反歸檔工具 NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:contentData]; //2.讀取檔案(需要執行歸檔方法) Person *p2 = [unArchiver decodeObjectForKey:@boyFriend]; NSLog(@%@,p2); //3.停止反歸檔 [unArchiver finishDecoding]; //4.釋放 [unArchiver release];
=======================數組和複雜物件結合==========================
建立數組:
Person *p3 = [[Person alloc]initWithName:@小美女 gender:@女 age:21]; Person *p4 = [[Person alloc]initWithName:@郭美美 gender:@女 age:19]; NSArray *pArray = @[p3,p4]; [p3 release]; [p4 release];
//注意:複雜物件存入數組要想完成歸檔,那麼存入的複雜物件必須遵循NSCoding協議
//使用歸檔把數組寫入到檔案
//1.建立歸檔工具 NSMutableData *aData = [NSMutableData data]; NSKeyedArchiver *nArchvier = [[NSKeyedArchiver alloc]initForWritingWithMutableData:aData]; //2.使用歸檔對象把數組歸檔 [nArchvier encodeObject:pArray forKey:@array]; //3.停止歸檔工具 [nArchvier finishEncoding]; //4.釋放 [nArchvier release];
//檔案寫入到Documents 檔案夾下,array.tet
NSString *arrayPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@array.text];isSuccess = [aData writeToFile:arrayPath atomically:YES]; NSLog(@%@,isSuccess ? @複雜數組寫入成功:@複雜數組寫入失敗);
//複雜數組的讀取
//複雜數組的讀取 NSData *newData = [NSData dataWithContentsOfFile:arrayPath]; //1.建立反歸檔工具 NSKeyedUnarchiver *nUnarchvier = [[NSKeyedUnarchiver alloc]initForReadingWithData:newData]; //2.通過key值將對象反歸檔 NSArray *newArray = [nUnarchvier decodeObjectForKey:@array]; //3.停止反歸檔工具 [nUnarchvier finishDecoding]; //4.釋放 [nUnarchvier release]; NSLog(@%@ %@,newArray[0],newArray[1]);