數據持久化的方式
1.屬性列表property.plist
2.NSUserDefaults(偏好設置)
3.write to file(寫入文件)
4.sqlite(iOS中的輕量級數據庫)
5.CoreData(蘋果基于sqlite封裝的數據管理方式)
可視化的源碼都是xml
documents:用來保存應用程序運行需要的持久化數據,通常是用戶固定需要的數據,iTunes在自動備份時會自動備份此文件夾。
// 參數
// 1.主路徑名稱
// 2.當前用戶(iOS端默認使用NSUserDomainMask)
// 3.是否使用絕對路徑
// YES絕對路徑-NO相對路徑~(Domain領域,區域)
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES) objectAtIndex:0];
library:通常用來存儲當前應用程序運行期間需要的一些內存,包括緩存和偏好設置。
NSString *libraryPath = NSSearchPathForDirectoriesInDomains(
NSLibraryDirectory,
NSUserDomainMask,
YES)[0];
caches:用來存放緩存文件,但是iTunes并不會備份此文件夾。
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(
NSCachesDirectory,
NSUserDomainMask,
YES)firstObject];
preferences:用來存儲應用的偏好設置,iTunes會自動備份此文件夾。
但是此文件夾不能被直接被尋找到,需要路徑拼接,因為我們一般不會直接操作保存用戶的偏好設置的內容,而是通過操作來使對應的代碼生效,然后存儲到這個文件夾。比如NSUserDefaults
NSString *preferencesPath = [NSSearchPathForDirectoriesInDomains(
NSPreferencePanesDirectory,
NSUserDomainMask,
YES)firstObject];
NSLog(@"%@",preferencesPath);// 能打印出來但是沒有此地址的數據
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setObject:@"游客" forKey:@"use_id"];
[ud setBool:YES forKey:@"NightModel"];
[ud setInteger:11 forKey:@"time"];
tmp:用來存放臨時文件的文件夾。程序運行期間有可能里面的文件會時不時消失掉,所以永遠不要使用此文件夾來存儲需要持久化得數據。iTunes不會備份此文件夾。
NSString *tmpPath = NSTemporaryDirectory();
包文件
// 路徑
NSString *bundlePath = [[NSBundle mainBundle]resourcePath];
NSLog( @"%@",bundlePath);
// 獲取包內文件
NSString *imagePath = [[NSBundle mainBundle]pathForResource:@"12" ofType:@"jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
簡單對象寫入文件
1.字符串寫入文件
NSString *incantation = @"I love my iOS teacher!";
NSString *path = [NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES)lastObject];
//path = [path stringByAppendingString:@"/a.txt"];//拼接地址文件
//path = [path stringByAppendingPathComponent:@"b.txt"];
path = [path stringByAppendingPathComponent:@"許晟馗@郝文舉.avi"];
//寫入文件
// 參數
// 1.路徑,傳入一個文件寫入的地方,并且提供文件名稱
// 2.YES為安全保護,在文件寫入時如果中斷了操作,那么操作恢復時可以保證文件的完整性。NO,不作任何保護。
// 3.數據寫入文件的編碼方式。
// 4.錯誤對象。
NSError *error = nil;
[incantation writeToFile:path
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
// 從文件中讀取
NSString *result = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:nil];
NSLog(@"%@",result);
全局屬性NSString *docPath;
self.docPath = [NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES)lastObject];
2.數組寫入文件
// 準備數組
NSArray *array = @[@1,@2,@3,@4];
// 準備即將寫入的路徑
NSString *path0 = [self.docPath stringByAppendingPathComponent:@"array"];
// 將數組寫入路徑
[array writeToFile:path0 atomically:YES];
// 根據路徑讀取數組
NSArray *resultArray = [NSArray arrayWithContentsOfFile:path0];
// 打印驗證結果
NSLog(@"%@",resultArray);
3.字典寫入
NSDictionary *dict = @{@"1":@"q",@"2":@"w",@"3":@"e"};
NSString *path1 = [self.docPath stringByAppendingPathComponent:@"dict"];
[dict writeToFile:path1 atomically:YES];
NSDictionary *resultDict = [NSDictionary dictionaryWithContentsOfFile:path1];
NSLog(@"%@",resultDict);
4.復雜對象寫入文件
// 二進制流文件寫入文件
UIImage *image0 = [UIImage imageNamed:@"12.jpg"];
// 使用JPEG的渲染方式將圖片轉化為二進制流
// 第一個參數為需要轉化的圖片,第二個為壓縮比例,范圍為0~1
// UIImagePNGRepresentation(UIImage * _Nonnull image)
NSData *data = UIImageJPEGRepresentation(image0, 1);
NSString *path2 = [self.docPath stringByAppendingPathComponent:@"aaa.jpg"];
[data writeToFile:path2 atomically:YES];
// 從文件中獲取圖片
UIImage *resultImage = [UIImage imageWithContentsOfFile:path2];
真正的深拷貝只有歸檔和反歸檔
SingleVip * s1 = [SingleVip new];
s1.name = @"張河山";
s1.age = 20;
s1.gender = @"male";
// 歸檔(將復雜對象轉化為NSData的方式)
// 創建可變的二進制流用來存放即將轉化的model數據
NSMutableData *mutdata = [NSMutableData new];
// 創建歸檔管理器,并制定要使用的可變二進制流控制器
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:mutdata];
// 歸檔操作(key值用于標記,方便飯歸檔時提取內容)
[archiver encodeObject:s1 forKey:@"s11"];
// 結束歸當操作
[archiver finishEncoding];
// 寫入文件
NSString *path6 = [self.docPath stringByAppendingPathComponent:@"s1"];
[mutdata writeToFile:path atomically:YES];
// 反歸檔
// 從文件中獲取NSData數據
NSData *data0 = [NSData dataWithContentsOfFile:path6];
// 創建反歸檔管理器,并制定要獲取的data數據來源
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc ]initForReadingWithData:data0];
// 反歸檔操作(根據歸檔時標記的key只操作)
SingleVip *s2 = [unarchiver decodeObjectForKey:@"s11"];
// 結束反歸檔
[unarchiver finishDecoding];
NSLog(@"%@-+-%@",s1,s2);
淺拷貝地址一樣,就是兩個指針指向同一地區,深拷貝地址不一樣,是因為重新開辟地區放入相同事物
SingleVip * s1 = [SingleVip new];
SingleVip * s2 = [SingleVip new];
/*
沒有真正意義上的深拷貝,除了歸檔和反歸檔,
因為可變數組的深拷貝雖然數組指針地址不同
但是里面同一個元素(model)的地址還是一樣。
*/
// 淺拷貝(不可變變不可變)
NSArray *array = @[s1,s2];
NSArray *_array = [array copy];
NSLog(@"%p-%p",array,_array);
// 深拷貝(不可變變可變)
NSArray *array1 = @[s1,s2];
NSMutableArray *mutArray = [array mutableCopy];
NSLog(@"%p-%p",array1,mutArray);
// 深拷貝(可變變不可變)
NSMutableArray *mutArray2 = [NSMutableArray arrayWithObjects:s1,s2, nil];
NSArray *array2 = [mutArray copy];// copy出的都是不可變的
NSLog(@"%p-%p",array2,mutArray2);
// 深拷貝(可變變可變)
NSMutableArray *mutArray3 = [mutArray2 mutableCopy];
NSLog(@"%p-%p",mutArray2,mutArray3);
SingleVip *s3 = [s1 copy];
NSLog(@"%p-%p",s1,s3);
SingleVip *s4 = [s1 mutableCopy];
NSLog(@"%p-%p",s1,s4);
點擊方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// 因為是單例,所以在程序的任何地方都可以獲取
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
// 可以獲取存儲在屬性列表里面的值,然后作相應的操作
if ([[ud objectForKey:@"use_id"] isEqualToString:@"游客"]) {
NSLog(@"尊敬的用戶請您登陸!");
}
}
自定義的model類創建的復雜對象,無法響應writeToFile消息,不能直接寫入文件。所以想要完成轉化,需遵循NSCoding協議,實現兩個編碼方法。
在歸檔過程中,需要自定義實現歸檔的細節,將簡單對象使用key值標記完成歸檔記錄
在反歸檔過程中,同樣需要根據歸檔記錄時的標記來解碼,完成屬性值的對應
.h
#import <Foundation/Foundation.h>
@interface SingleVip : NSObject<NSCoding,NSCopying,NSMutableCopying>
@property(strong,nonatomic,nonnull)NSString *name;
@property(assign,nonatomic)NSInteger age;
@property(strong,nonatomic,nullable)NSString *gender;
@end
.m
#import "SingleVip.h"
@implementation SingleVip
// 歸檔(編碼)
- (void)encodeWithCoder:(NSCoder *)aCoder
{
// 逐條
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInteger:_age forKey:@"age"];
[aCoder encodeObject:_gender forKey:@"gender"];
}
// 反歸檔(解碼)
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
_name = [aDecoder decodeObjectForKey:@"name"];
_age = [aDecoder decodeIntegerForKey:@"age"];
_gender = [aDecoder decodeObjectForKey:@"gender"];
}
return self;
}
// 要實現深淺拷貝,首先要遵循NSCopying協議,然后寫一下方法->copyWithZone
/*
- (id)copyWithZone:(NSZone *)zone{
// 淺拷貝直接返回self
return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
return self;
}
*/
- (id)copyWithZone:(NSZone *)zone{
// 深拷貝
id obj = [[[self class] allocWithZone:zone] init];
return obj;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
// 深拷貝
id obj = [[[self class] allocWithZone:zone] init];
return obj;
}
@end