概要
四种方式:
1. NSKeyedArchiver归档(NSCoding)序列化
2. NSUserDefaults:用来保存应用程序设置和属性、用户保存的数据。
3. NSFileManager write 的方式直接写入磁盘
4. SQLite:采用SQLite数据库来存储数据
一、NSKeyedArchiver归档(NSCoding)序列化
需要归档解档的类需要遵守NSCoding协议,只有遵守了NSCoding协议的类才可以用NSKeyedArchiver归档和NSKeyedUnarchiver解档。
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver归档和NSKeyedUnarchiver解档~
缺点:归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能
针对小量数据,而且对数据操作比较 笨拙,即如果想改动数据的某一小部分,还
是需要解压整个数据或者归档整个数据。
实现归档的四个步骤
1.遵守NSCoding协议
2.实现encodeWithCoder和initWithCoder方法
3.归档方法
4.解档方法
1.1 遵守NSCoding协议
@interface CreateTrainOnlineCache : NSObject<NSCoding>
1.2 实现encodeWithCoder和initWithCoder方法
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:self.name forKey:@"name"];
[coder encodeInteger:self.age forKey:@"age"];
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
self.age = [coder decodeIntegerForKey:@"age"];
self.name = [coder decodeObjectForKey:@"name"];
}
return self;
}
1.3 归档
Student *s1 = [[Student alloc] init];
s1.name = @"zzz";
s1.age = 18;
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 这个文件后缀可以是任意的,只要不与常用文件的后缀重复即可,我喜欢用data
NSString *filePath = [path stringByAppendingPathComponent:@"student.data"];
// 归档
[NSKeyedArchiver archiveRootObject:s1 toFile:filePath];
1.4 解档
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
NSString *filePath = [path stringByAppendingPathComponent:@"student.data"];
// 解档
Student *s = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"%@----%ld", s.name, s.age);
1.5 扩展
1.5.1 用户数据隔离
这里笔者的应用涉及到多用户切换,多用户数据之间相对隔离保密。这里笔者在用户登录app时便以用户登录名为文件名创立了用户目录,读取都在这个个文件目录,不同的用户在沙盒的目录不同,以达到用户数据隔离的效果。
#import "NSFileManager+Paths.h"
-(NSString *)userPath{
NSString *path = [NSString stringWithFormat:@"%@/%@",[NSFileManager documentsPath],[self account]];
return path;
}
#pragma mark - 类文件本地归档
-(void)saveCache{
NSString *userPath = [BSEUserInfo shareMannager].userPath;
NSString *filePath = [userPath stringByAppendingPathComponent:@"onlineTrain.data"];
[NSKeyedArchiver archiveRootObject:self toFile:filePath];
}
-(void)deleteCache{
NSFileManager* fileManager = [NSFileManager defaultManager];
NSString *userPath = [BSEUserInfo shareMannager].userPath;
NSString *filePath = [userPath stringByAppendingPathComponent:@"onlineTrain.data"];
BOOL fileExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (!fileExist) {
NSLog(@"not exist");
return ;
}else {
NSLog(@"exist");
BOOL deleteState = [fileManager removeItemAtPath:filePath error:nil];
if (deleteState) {
NSLog(@"delete success");
}else {
NSLog(@"delete fail");
}
}
}
#pragma mark - 加载本地归档
-(BOOL)loadCache{
NSString *userPath = [BSEUserInfo shareMannager].userPath;
NSString *filePath = [userPath stringByAppendingPathComponent:@"onlineTrain.data"];
BOOL fileExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (!fileExist) {
NSLog(@"not exist");
return NO;
}else {
CreateTrainOnlineCache *object = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
share = object;
return YES;
}
}
1.5.2 使用runtime动态获取类属性减少冗余代码
#import <objc/runtime.h>
/**
* 根据类动画获取类的所有属性,不要忘记导入#import <objc/runtime.h>
*
* @param cls <#cls description#>
*
* @return <#return value description#>
*/
- (NSArray *)perperiesWithClass:(Class)cls
{
NSMutableArray *perperies = [NSMutableArray array];
unsigned int outCount;
//动态获取属性
objc_property_t *properties = class_copyPropertyList(cls, &outCount);
//遍历person类的所有属性
for (int i = 0; i < outCount; i++)
{
objc_property_t property = properties[i];
const char *name = property_getName(property);
NSString *s = [[NSString alloc] initWithUTF8String:name];
[perperies addObject:s];
}
return perperies;
}
/**
* 归档会触发
*
* @param aCoder <#aCoder description#>
*/
- (void)encodeWithCoder:(NSCoder *)aCoder
{
for (NSString *perperty in [self perperiesWithClass:[self class]])
{
[aCoder encodeObject:perperty forKey:perperty];
}
}
/**
* 解归档会触发
*
* @param aDecoder <#aDecoder description#>
*
* @return <#return value description#>
*/
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init])
{
for (NSString *perperty in [self perperiesWithClass:[self class]])
{
[self setValue:[aDecoder decodeObjectForKey:perperty] forKey:perperty];;
}
}
return self;
}
二、NSUserDefaults 偏好设置
- NSUserDefaults 是一个单例对象,在整个应用程序的生命周期中都只有一个实例。
- NSUserDefaults保存的数据类型有:
(1). 基本数据类型(int,NSInter,float,double,CGFlat......)
(2). NSNumber, NSString, NSData, NSArray, NSDictionary, NSURL。
- 其他类要是想适使用NSUserDefaults 存储到本地需要 转换成相应的数据类型才行。如UIImage:
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
UIImage *image=[[UIImage alloc]initWithContentsOfFile:@"photo.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 100);//UIImage对象转换成NSData
[defaults setObject: imageData forKey:@"image"];
[defaults synchronize];//立即保存
- synchronize。立即保存
苹果文档这么说:
Writes any modifications to the persistent domains to disk and updates all unmodified persistent domains to what is on disk.
Return Value YES if the data was saved successfully to disk, otherwise NO.
非必要函数,一般写入工作后会触发保存。
应用:
NSUserDefaults一般保存配置信息,比如用户名、密码、是否保存用户名和密码、是否离线下载等一些配置条件信息。
这个相信大家都用过,就不细讲了,直接上方法。
2.1 写入:
//(1)基本数据类型
//保存NSInteger
[defaults setInteger:(NSInteger) forKey:(nonnull NSString *)];
//保存BOOL
[defaults setBool:(BOOL) forKey:(nonnull NSString *)];
//(2)对象
[defaults setObject:@"用户名" forKey:kUsernameKey];
2.1 读取:
//(1)基本数据类型
//保存NSInteger
[defaults setInteger:(NSInteger) forKey:(nonnull NSString *)];
//保存BOOL
[defaults setBool:(BOOL) forKey:(nonnull NSString *)];
//(2)对象
NSString *username = [defaults objectForKey:kUsernameKey];
2.3 删除
//删除指定key的数据
[defaults removeObjectForKey:(nonnull NSString *)];
三、plist文件保存
* plist本身就是XML文件,名字后缀为.plist。
* plist主要保存的数据类型为NSString、NSNumber、NSData、NSArray、NSDictionary。
实现方法:
3.1 写入
/把字典写入到plist文件,比如文件path为:~/Documents/data.plist
[dictionary writeToFile:path atomically:YES];
//把数组写入到plist文件中
[array writeToFile:path atomically:YES];
3.2 读取
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:(nonnull NSString *)]];
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:(nullable NSString *) ofType:(nullable NSString *)]];
四、 SQLite数据库
这个有些非常好用的第三方库,很常见就不多讲了直接上连接。
FMDB
这里推荐一个基于FMDB 封装的第三方LKDBHelper,大大简化了数据库的操作。
LKDBHelper-SQLite-ORM
数据库将会在后面再详细总结下,贴出常用的建表 增删查改方法。
五、 CoreData
1 . CoreData提供了一种“对象-关系映射”的功能,能将OC对象转化成数据,保存Sqlite中。
2 . CoreData的好处就是能够合理管理内存,避免sql语句的麻烦(不用写sql语句)。
CoreData构成
- NSManagedObjectContext:被管理的数据上下文,主要作用:插入、查询、删除。
- NSManagedObjectModel:数据库所有的表结构和数据结构,包含各个实体的定义的信息。主要作用就是添加实体、实体属性,建立属性之间的关系。
- NSPersistentStoreCoordinator持久化存储助理对象,相当于数据库的连接器。主要作用就是设置存储的名字、位置、存储方式。
- NSFetchRequest相当于select语句。查询封装对象。
- NSEntityDescription实体结构对象,相当于表格结构。
- 后缀为xxx.xcdatamodeld文件,编译后为xxx.momd的文件。
创建工程的时候,勾上Use Core Data。如图所示
六、 KeyChain
- 钥匙串(英文: KeyChain)是苹果公司Mac OS中的密码管理系统。
- 一个钥匙串可以包含多种类型的数据:密码(包括网站,FTP服务器,SSH帐户,网络共享,无线网络,群组软件,加密磁盘镜像等),私钥,电子证书和加密笔记等。
- iOS的KeyChain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式。每个iOS程序都有一个独立的KeyChain存储。从iOS 3.0开始,跨程序分享KeyChain变得可行。
- 当应用程序被删除后,保存到KeyChain里面的数据不会被删除,所以* * KeyChain是保存到沙盒范围以外的地方。
- KeyChain的所有数据也都是以key-value的形式存储的,这和NSDictionary的存储方式一样。
- 相比于NSUserDefaults来说,KeyChain保存更为安全,而且KeyChain里面保存的数据不会因为app删除而丢失