iOS应用程序数据的持久化
文章目录
# 前言 一个功能丰富的应用程序,它的数据不仅存在于内存中,而是将更多的数据写入磁盘,进行持久化存储,例如存储用户的历史信息、保存游戏进度和得分情况等。 iOS数据持久化方式基本上有4种:plist属性列表、对象归档、SQLite3和Core Data。本文主要介绍如何创建和解析plist文件,以及如何使用Core Data框架对数据进行存储、查找、编辑和删除操作。 本文用OC来进行数据持久化操作
plist文件
plist文件的全名为Property List即属性列表文件,它是一种用来存储串行化后的对象文件,由于属性列表文件的扩展名为plist,因此通常被简称为plist文件。
1.创建plist文件
首先创建一个基于【Single View Application】模板的空白项目,然后【New File】一个Property List文件
右键【Add Row】添加一行新的键值对
我们设置Name:Pteer和Age:24两个键值对,设置对应的数据类型,我们看到plist支持红框中的几种数据类型
2.解析plist文件
NSString *path = [[NSBundle mainBundle] pathForResource:@"demoPlist" ofType:@"plist"];
NSDictionary *data = [[NSDictionary alloc] initWithContentsOfFile:path];
NSLog(@"%@",data);
输出
2021-03-09 20:01:30.356601+0800 PListProject[64277:23229145] {
Age = 24;
Name = Peter;
}
3.将数据写入plist文件
NSMutableDictionary *dictM = [[NSMutableDictionary alloc] init];
[dictM setObject:@"Johnny" forKey:@"Name"];
[dictM setObject:@"23" forKey:@"Age"];
[dictM setObject:@"183" forKey:@"Height"];
NSString *path = [[NSBundle mainBundle] pathForResource:@"demoPlist" ofType:@"plist"];
[dictM writeToFile:path atomically:true];
NSDictionary *data = [[NSDictionary alloc] initWithContentsOfFile:path];
NSLog(@"%@",data);
2021-03-09 20:14:44.729928+0800 PListProject[80790:23284101] {
Age = 23;
Height = 183;
Name = Johnny;
}
使用Core Data进行数据的持久化
Core Data是一个Cocoa框架,用于存储和管理应用程序中MVC模式中的模型数据。
Core Data框架中包含了Fetch Request数据查询请求、ManagedObjectContext托管对象上下文、Persistent Store Coordinate持久化存储协调器和Persistent Store持久化存储等概念。
1.创建Core Data实体并插入数据
首先要想在项目中使用Core Data技术,需要引入Core Data框架,或者在创建新项目时选中【Core Data】选项。
2.编写一个数据操作工具类
详细的代码逻辑就不一一介绍啦,基本每一块都有注释
CoreDataManager.h
//
// CoreDataManager.h
// PListProject
//
// Created by homilyiosthour on 2021/3/9.
// Copyright © 2021 homilyiosthour. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
NS_ASSUME_NONNULL_BEGIN
@interface CoreDataManager : NSObject
/// 上下文容器 存放的是所有从数据库中取出的转换成OC对象
@property (strong, nonatomic) NSManagedObjectContext * managedObjectContext;
/// 读取解析 ,momd 文件中的内容
@property (strong, nonatomic) NSManagedObjectModel * managedObjectModel;
/// 连接的类,处理数据库数据和OC数据底层的相互转换
@property (strong, nonatomic) NSPersistentStoreCoordinator * persistentStoreCoordinator;
/// 单例
+ (instancetype)sharedInstance;
/// 插入数据
/// @param dict 字典中的键值对必须要与实体中的每个名字一一对应
/// @param success 成功回调
/// @param fail 失败回调
- (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
/// 更新方法
/// @param success 成功
/// @param fail 失败
- (void)updateEntity:(void (^)(void))success fail:(void (^)(NSError *))fail;
- (void)selectEntity:(NSArray *)selectKeys ascending:(BOOL)isAscending filterString:(NSString *)filterString success:(void(^)(NSArray *))success fail:(void (^)(NSError *))fail;
- (void)deleateEntity:(NSManagedObject *)model success:(void (^)(void))success fail:(void(^)(NSError *))fail;
@end
NS_ASSUME_NONNULL_END
CoreDataManager.m
//
// CoreDataManager.m
// PListProject
//
// Created by homilyiosthour on 2021/3/9.
// Copyright © 2021 homilyiosthour. All rights reserved.
//
#import "CoreDataManager.h"
//获取CoreData的.xcdatamodel文件的名称
static NSString * const coreDataModelName = @"CoreDataText";
//获取CoreData
static NSString * const coreDataEntityName = @"User";
//数据库
static NSString * const sqliteName = @"User.sqlite";
@implementation CoreDataManager
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
static CoreDataManager * coreDataManager = nil;
+ (instancetype)sharedInstance{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coreDataManager = [[CoreDataManager alloc] init];
});
return coreDataManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (coreDataManager == nil) {
coreDataManager = [super allocWithZone:zone];
}
});
return coreDataManager;
}
- (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail{
//判断字典是否为空
if(!dict||dict.allKeys.count == 0) return;
//通过传入上下文和实体名称,创建一个名称对应的实体对象(相当于数据库一组数据,其中含有多个字段)
NSManagedObject *entity = [NSEntityDescription insertNewObjectForEntityForName:coreDataEntityName inManagedObjectContext:self.managedObjectContext];
//实体对象存储属性值(相当于数据库中将一个值存入对应字段)
for (NSString *key in [dict allKeys]) {
[entity setValue:[dict objectForKey:key] forKey:key];
}
//保存信息,同步数据
NSError *error = nil;
BOOL result = [self.managedObjectContext save:&error];
if (!result) {
NSLog(@"添加数据失败:%@",error);
if (fail) {
fail(error);
}
}else{
NSLog(@"添加数据成功");
if(success){
success();
}
}
}
- (void)deleateEntity:(NSManagedObject *)model success:(void (^)(void))success fail:(void(^)(NSError *))fail{
//传入要删除的实体对象
[self.managedObjectContext deleteObject:model];
//同步到数据库
NSError *error = nil;
[self.managedObjectContext save:&error];
if (error) {
NSLog(@"删除失败:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"删除成功");
if (success) {
success();
}
}
}
- (void)selectEntity:(NSArray *)selectKeys ascending:(BOOL)isAscending filterString:(NSString *)filterString success:(void(^)(NSArray *))success fail:(void (^)(NSError *))fail{
//1.初始化一个查询请求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
//2.设置要查询的实体
NSEntityDescription *desc = [NSEntityDescription entityForName:coreDataEntityName inManagedObjectContext:self.managedObjectContext];
request.entity = desc;
//3.设置查询结果排序
if (selectKeys && selectKeys.count>0) {//如果进行了设置排序
NSMutableArray *array = [NSMutableArray array];
for (NSString *key in selectKeys) {
/**e'Key'yeKeyy
设置查询结果排序
sequenceKey:根据某个属性(相当于数据库某个字段)来排序
sequenceKe'y:是否升序
*/
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:key ascending:isAscending];
[array addObject:sort];
}
if (array.count>0) {
request.sortDescriptors = array;//可以添加多个排序描述器。然后按顺序放进数组即可
}
}
//4.设置条件过滤
if (filterString) {//如果设置了过滤语句
NSPredicate *predicate = [NSPredicate predicateWithFormat:filterString];
request.predicate = predicate;
}
//5.执行请求
NSError *error = nil;
//获得查询数据数据集合
NSArray *objs = [self.managedObjectContext executeFetchRequest:request error:&error];
if (error) {
NSLog(@"失败");
if (fail) {
fail(error);
}
}else{
NSLog(@"成功");
if (success) {
success(objs);
}
}
}
/// 更新方法
/// @param success 成功
/// @param fail 失败
- (void)updateEntity:(void (^)(void))success fail:(void (^)(NSError *))fail{
NSError *error = nil;
[self.managedObjectContext save:&error];
if (error) {
NSLog(@"更新失败");
if (fail) {
fail(error);
}
} else {
if (success) {
success();
}
}
}
// 懒加载
/// 属性的getter方法
- (NSManagedObjectModel *)managedObjectModel{
if(_managedObjectModel == nil){
//.xcdatamodeld文件 编译之后变成.model文件(.mom)文件
NSURL *modelUrl = [[NSBundle mainBundle] URLForResource:coreDataModelName withExtension:@"momd"];
//把文件的内容读取到managedObjectModel中
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelUrl];
}
return _managedObjectModel;
}
/// 调度者负责数据库的操作 创建数据库 打开数据 增删改查数据
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
if (!_persistentStoreCoordinator) {
//根据model创建了persistentStoreCoordinator
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
//设置数据库存放的路径
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:sqliteName];
NSError *error = nil;
//如果没有得到数据库,程序崩溃
/*
持久化存储库的类型:
NSSQLiteStoreType SQLite数据库
NSBinaryStoreType 二进制平面文件
NSInMemoryStoreType 内存库,无法永久保存数据
虽然这3种类型的性能从速度上来说都差不多,但从数据模型中保留下来的信息却不一样
在几乎所有的情景中,都应该采用默认设置,使用SQLite作为持久化存储库
*/
//添加一个持久化存储库并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
if (error) {
NSLog(@"添加数据库失败:%@",error);
}else{
NSLog(@"添加数据库成功");
}
NSLog(@"错误信息:%@,%@",error,[error userInfo]);
}
}
return _persistentStoreCoordinator;
}
/// 获取沙盒路径下documents文件夹的路径 NSURL
-(NSURL *)applicationDocumentsDirectory
{
//获取沙盒路径下documents文件夹的路径 NSURL (类似于search)
NSLog(@"%@",[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject].absoluteString);
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
/// 容器类 存放OC的对象
- (NSManagedObjectContext *)managedObjectContext{
if (!_managedObjectContext) {
NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator];
if (!coordinator)
{
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
//让context和coordinator关联 context可以和数据进行增删改查功能
//设置上下文所要关联的持久化存储库
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
@end
调用数据管理类
//添加插入数据
NSDictionary *dict = @{@"userName":@"wzx",@"password":@"123456"};
[[CoreDataManager sharedInstance] insertNewEntity:dict success:^{
NSLog(@"添加成功");
} fail:^(NSError * _Nonnull error) {
NSLog(@"添加失败");
}];
//查询数据
[[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray * result) {
NSLog(@"查询成功:%@",result);
} fail:^(NSError * error) {
NSLog(@"查询失败%@",error);
}];
//查询数据
NSString *filterString = [NSString stringWithFormat:@"userName='wzx'"];
[[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:filterString success:^(NSArray * result) {
NSLog(@"查询成功:%@",result);
} fail:^(NSError * error) {
NSLog(@"查询失败%@",error);
}];
控制台输出结果
2021-03-15 20:49:06.495996+0800 CoreDataText[3308:350741] 添加成功
2021-03-15 20:49:06.496408+0800 CoreDataText[3308:350741] 查询成功:(
"<User: 0x2822cc960> (entity: User; id: 0xd8940d2834044e18 <x-coredata://6B28376E-53C7-4E97-A8F2-3243DF330828/User/p1>; data: {\n password = 123456;\n userName = wzx;\n})"
)
2021-03-15 20:49:06.496746+0800 CoreDataText[3308:350741] 查询成功:(
"<User: 0x2822cc960> (entity: User; id: 0xd8940d2834044e18 <x-coredata://6B28376E-53C7-4E97-A8F2-3243DF330828/User/p1>; data: {\n password = 123456;\n userName = wzx;\n})"
)
参考:
《iOS移动开发从入门到精通》
ios CoreData的使用(封装):https://blog.youkuaiyun.com/u013983033/article/details/83378838