数据持久化的方式
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