注意: 以下方法适用于iOS10+ swift版本
启用
新建工程时勾选use core data
对于已创建工程,可以新建一个带有core data
的工程,拷贝appDelegate
中coredata
相关代码。然后更改项目名,加入import coreData
即可
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
//创建持久化容器
let container = NSPersistentContainer(name: "StructDemo")
//载入
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
//失败时报错
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
//获取容器上下文
let context = persistentContainer.viewContext
//改变时保存
if context.hasChanges {
do {
//保存
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//失败时错误处理
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
可视化建模
- 注意图片类型为
binary data
- 注意设置类型
optional
- 注意把实体(Entity)的
class name
改成原名字后面加MO(AreaMO),代码中Area
替换成AreaMO
手动生成类文件
使用可视化建模会自动生成相应文件,但是会隐藏不会显示。
可以通过设置实体属性来阻止自动生成。
通过手动来创建文件
这样就可以在创建文件中进行编辑,加入自定义方法。例如传统模型中实现的字典转模型的代理方法等
Relationship
双向关系,一对多。可根据实际情况修改
新增
let appDelegate = UIApplication.shared.delegate as! AppDelegate
area = AreaMO(context: appDelegate.persistentContainer.viewContext)
area.name = nameTextField.text
area.province = provinceTextField.text
area.part = partTextField.text
area.isVisited = self.isVisited
if let imageData = coverImageView.image?.jpegData(compressionQuality: 0.7) {
area.image = imageData
}
print("正在保存")
appDelegate.saveContext()
performSegue(withIdentifier: "unwindToHomeList", sender: self)
查找全部
func fetchAllData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
do {
//取回后保存在数组中
areas = try appDelegate.persistentContainer.viewContext.fetch(AreaMO.fetchRequest())
} catch {
print(error)
}
}
每次更新修改单条数据,都查找全部数据,会造成性能上的浪费,使用一下方法,进行性能优化
NSFetchedResultsController关联
定义变量
var fetchedController: NSFetchedResultsController<AreaMO>!
实现如下方法,并在viewDidLoad
中调用
func fetchedControllerFetchData(){
//初始化请求并设定请求结果类型为AreaMO
let request: NSFetchRequest<AreaMO> = AreaMO.fetchRequest()
//排序方式
let sortDesc = NSSortDescriptor(key: "name", ascending: true)
request.sortDescriptors = [sortDesc]
//获取上下文
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
//根据请求和上下文初始化查询结果控制器
fetchedController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
fetchedController.delegate = self
//执行查询,失败打印错误,成功将结果保存在数组中
do {
try fetchedController.performFetch()
if let objects = fetchedController.fetchedObjects {
areas = objects
}
} catch {
print(error)
}
}
遵循代理NSFetchedResultsControllerDelegate
实现如下代理方法:
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
//将要变更
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
//已经变更
tableView.endUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
//正在变化
//根据类型筛选
switch type {
//删除指定行
case .delete:
tableView.deleteRows(at: [indexPath!], with: .automatic)
//插入指定行
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .automatic)
//更新指定行
case .update:
tableView.reloadRows(at: [indexPath!], with: .automatic)
//默认全部更新
default:
tableView.reloadData()
}
//同时更新内存数据
if let objects = controller.fetchedObjects {
areas = objects as! [AreaMO]
}
}
删除
因为NSFetchedResultsController
的代理方法中,有根据数据变化对单元格进行删除的操作,所以这里不再需要原来的删除操作。避免多次进行单元格删除操作造成崩溃。
let rowActionDelete = UITableViewRowAction(style: .destructive, title: "删除") { (_, _) in
// self.areas.remove(at: indexPath.row)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
context.delete(self.fetchedController.object(at: indexPath))
appDelegate.saveContext()
// tableView.deleteRows(at: [indexPath], with: .automatic)
}
更新
在数据更新页面更新数据退出的时候,也就是在如下更新页面退场的方法中,执行一次保存操作。
@IBAction func closeReview(segue:UIStoryboardSegue) {
let reviewVC = segue.source as! ReviewViewController
if let rating = reviewVC.rating {
area.rating = rating
ratingButton.setImage(UIImage(named: rating), for: .normal)
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.saveContext()
}
注意:以下为早期OC版本代码
1.查找全部
- (NSMutableArray) findAll
{
获取上下文
NSManagedObjectContext *cxt = [self managedObjectContext];
根据上下文建立实体描述
NSEntityDescription *entityDescription = [NSEntityDescription entityForName@"Note" inManagedObjecctContext:cxt];
根据实体描述建立请求
NSFetchRequset *request = [[NSFetchRequset alloc] init];
[request setSortDescriptors:@[sortDescriptor]];
建立用于装错误信息的error地址
NSError *error = nil;
在上下文中根据请求从数据库中取得装有NoteManagedObject对象的数组
NSArray *listData = [cxt executeFestchRequest:request error:&error];
建立准备装有目标模型的数组
NSMutableArray *resListData = [[NSMutableArray alloc] init];
重装
for(BoteManagedObject *mo in listData){
Note *note = [[Note alloc] init];
note.date = mo.date;
mote.content = mo.content;
[resListDate addObject:note];
}
return resListData;
}
2.条件查找
- (NSMutableArray) findById:(Note *)model
{
获取上下文
NSManagedObjectContext *cxt = [self managedObjectContext];
根据上下文建立实体描述
NSEntityDescription *entityDescription = [NSEntityDescription entityForName@"Note" inManagedObjecctContext:cxt];
根据实体描述建立请求
NSFetchRequset *request = [[NSFetchRequset alloc] init];
[request setSortDescriptors:@[sortDescriptor]];
添加具体的查找条件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"date = %@" , model.date];
[request setPredicate : predicate];
建立用于装错误信息的error地址
NSError *error = nil;
在上下文中根据请求从数据库中取得装有NoteManagedObject对象的数组
NSArray *listData = [cxt executeFestchRequest:request error:&error];
建立准备装有目标模型的数组
NSMutableArray *resListData = [[NSMutableArray alloc] init];
重装
for(BoteManagedObject *mo in listData){
Note *note = [[Note alloc] init];
note.date = mo.date;
mote.content = mo.content;
[resListDate addObject:note];
}
return resListData;
}
3.增加数据
- (int)creat:(Note*)model
{
NSManagedObjectContext *cxt = [self managedObjectContext];
建立新的
NoteManagedObject *note = [NSEntityDescription insertNewObjectForEntityForName:@"Note" inManagedObjectContext:cxt];
[note setValue: model.content forKey:@"content"];
[note setValue: model.date forKey:@"date"];
note.date = model.date;
note.content = model.content;
NSError *savingError = nil;
if([self.managedObjectContext save:&savingError]){
NSLog(@"插入数据成功");
} else {
NSLog(@"插入数据失败");
return -1;
}
retrun 0;
}
4.删除数据
- (int) remove:(Note*)model
{
NSManagedObjectContext *cxt = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Note" inManagedObjectCOntext:cxt];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate prediccateWithFormat:@"date = %@" , model.date];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *listData = [cxt executeFetchRequest:request error:&error];
if([listData count] > 0){
NoteManagedObject *note = [listData lastObject];
[self.managedObjectContext deleteObject:note];
NSError *savingError = nil;
if([self.managedObjectContext save:&savingError]){
NSLog(@"删除数据成功");
} else{
NSLog(@"删除数据失败");
return -1;
}
}
return 0;
}
5.修改数据
-(int)modify:(Note*)model
{
NSManagedObjectContext *cxt = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Note" inManagedObjectContext:cxt];
NSFetchRequest *request = [[NSFetchRequset alloc] init];
[requset setEntity:entityDescription];
NSError *error = nil;
NSArray *listData = [cxt executeFetchRequest:request error:&error];
if([listData count] > 0){
NoteManagedObject *note = [listData lastObject];
note.content = model.content;
NSError *savingError = nil;
if([self.managedObjectContext save:&savingError]){
NSLog(@"修改数据成功");
}else{
NSLog(@"修改数据失败");
return -1;
}
}
return 0;
}