【ios笔记】CoreData
文章目录
- 参考
- 概念
- 1.基础
- 2. NSPersistentContainer
- 3.NSManagedObjectModel
- 4.NSManagedObjectContext
- 5.NSPersistentStoreCoordinator
- 应用:使用`预置sqlite`数据文件
- 使用CoreData
- 1.创建CoreData模型
- 2.初始化NSPersistentContainer
- 3.增删改查
- 4.更多查询用法
- Predicate编程
- 1.创建Predicate
- 2.使用Predicate
- 3.字符串语法
- 多线程
- 1.异步请求
- 2.后台任务
- 批量处理
- 1.批量更新
- 2.批量删除
- 3.批量插入
参考
官方文档-API
官方文档-CoreData编程指南(快速入门)
官方文档-Predicate编程指南(查询语句)
简书上的小例子(快速入门)
Core Data性能优化及多上下文操作
初识Core Data(4):批量操作、聚合操作、WWDC 2015新特性
概念
1.基础
- CoreData是对Sqlite的封装,提供上层Api操作数据库
- CoreDataStack:包括
NSManagedObjectModel
,NSPersistentStoreCoordinator
,NSManagedObjectContext
- NSPersistentContainer管理CoreDataStack
2. NSPersistentContainer
- 简介:负责创建和管理
NSManagedObjectModel
,NSPersistentStoreCoordinator
,NSManagedObjectContext
。创建NSPersistentContainer并调用loadPersistentStores后就同时创建了以上三个实例,所以通过container可以获取上面3个实例的全部内容。一个app实例共享一个container,因此可以将container放入AppDelegate中。 - 相关属性和方法
属性或方法 | 解释 |
---|---|
NSPersistentContainer(name: “TestCoreData”) | 初始化container,name为TestCoreData.xcdatamodeld的文件名 |
container.persistentStoreDescriptions | 返回(type: SQLite, url: xxx.sqlite)底层为sqlite储存,url为sqlite文件储存路径 |
container.loadPersistentStores { (description, err) in } | 指示加载sqlite文件信息到内存,即初始化CoreDataStack,不加载具体数据行 |
container.managedObjectModel | 获取model实例 |
container.persistentStoreCoordinator | 获取coordinator实例 |
NSPersistentContainer.defaultDirectoryURL() | sqlite文件的默认储存路径 |
container.viewContext | 主队列的context |
container.newBackgroundContext() | 创建新的后台context |
3.NSManagedObjectModel
- 简介:.xcdatamodeld描述对象的文件的程序化表示,即NSManagedObjectModel的实例代表文件中描述的全部内容,包括entities(所有实体)
- 相关属性和方法
属性或方法 | 解释 |
---|---|
model.entities | 返回NSEntityDescription数组,即在.xcdatamodeld中的每个实体描述 |
model.entitiesByName | 返回字典数组,key为实体名,值为NSEntityDescription |
- NSEntityDesription
实体描述
//获取实例
model.entitiesByName["实体名"]
//或者
NSEntityDescription.entity(forEntityName: "实体名", in: context)
- NSManagedObject
实体的实例
//初始化,以User为例
let user = NSEntityDescription.insertNewObject(forEntityName: "User", into: context) as! User
//或者
let user = User(entity: objectModel.entitiesByName["User"]!, insertInto: context)
4.NSManagedObjectContext
属性或方法 | 解释 |
---|---|
fetch(NSFetchRequest) | 获取符合条件的对象数组 |
count(NSFetchRequest) | 符合条件的对象数组的大小 |
registeredObject(NSManagedObjectID) | 通过id获取对象 |
object(NSManagedObjectID) | 通过id获取对象 |
existingObject(NSManagedObjectID) | 通过id获取对象 |
registeredObjects(Set<NSManagedObject>) | 把对象集合注册到context |
insertedObjects | 已插入,还未保存的对象 |
updatedObjects | 已提交更新,还未保存的对象 |
deletedObjects | 已提交删除,还未保存的对象 |
insert((NSManagedObject)) | 插入 |
delete(NSManagedObject) | 删除 |
save() | 提交更变 |
hasChanges | 是否有未提交的更变 |
undo() | 撤销未提交的更改 |
redo() | 撤销undo |
reset() | 将context恢复为基本状态 |
rollback() | 回滚,放弃所有插入和删除操作 |
perform(){} | 在context队列中异步执行块 |
performAndWait(){} | 在context队列中同步执行块 |
5.NSPersistentStoreCoordinator
- 帮助
context
和persistentStore
(sqlite文件
)通信 应用:使用
预置sqlite
数据文件
//1.将存有数据的sqlite数据库文件放入项目中
//2.替换persistentStoreDescriptions
container.persistentStoreDescriptions=[NSPersistentStoreDescription(url: Bundle.main.url (forResource: "文件名", withExtension: "sqlite")!)]
//3.加载预置的sqlite文件
container.loadPersistentStores(){ (description, err) inprint("load description:\(description)")print("load err:\(err.debugDescription)")}
使用CoreData
1.创建CoreData模型
- 新建DataModel文件
– 命名为项目名.xcdatamodeld
- 添加entity
– Add Entity - 添加属性
– 添加完属性后在entity的inspector页面添加Constrains主键
- 添加关系
– 如果该实体包含另一个实体,则可以在relationships中添加 - 生成代码
– 自动生成
在entity的inspector页面,codegen中选中Class Definition
,这样xcode将会自动生成NSManagedObjectModel代码,直接使用即可,不用再手动生成
– 手动生成
也可以选中Manual/None
,这样需要点击Editor->create NSManagedObject Subclass
手动生成代码
//以User的CURD为例
1.新建项目TestCoreData
2.新建文件TestCoreData.xcdatamodeld
3.添加entity:User
4.添加属性:id,integer64;name,String
5.User 的codegen为ClassDefinition,Constrains 为id
2.初始化NSPersistentContainer
//在AppDelegate.swift中,全局化初始NSPersistentContainer
lazy var persistentContainer: NSPersistentContainer = {let container = NSPersistentContainer(name: "TestCoreData")container.loadPersistentStores(completionHandler: { storeDescription, error inprint ("storeDescription:\(storeDescription)")if let error = error as NSError? {fatalError("Unresolved error \(error), \(error.userInfo)")}})return container}()//在页面中获取container的引用
(UIApplication.shared.delegate as! AppDelegate).persistentContainer
3.增删改查
- 增
//step1.创建NSManagedObject
//方法一:
let user = NSEntityDescription.insertNewObject(forEntityName: "User", into: context) as! User
//方法二:
let user = User(entity: objectModel.entitiesByName["User"]!, insertInto: context)//step2.赋值
user.id = 1
user.name = "a"//step3.提交更改
do{try context.save()
}catch{print("save error:\(error)")
}
- 查
//查询user的name为a的记录
let fetchReq = NSFetchRequest<User>(entityName: "User")fetchReq.predicate = NSPredicate(format: "name==%@", "a")do {let users = try context.fetch(fetchReq)for user in users {print(user.toStr())}} catch{print("fetch error:\(error)")}
- 更新
//把name为b的修改为c
let fetchReq = NSFetchRequest<User>(entityName: "User")fetchReq.predicate = NSPredicate(format: "name==%@", "b")do {let users = try context.fetch(fetchReq)for user in users {user.name = "c"}try context.save()} catch{print("error:\(error)")}
- 删除
//删除name为b的全部记录
let fetchReq = NSFetchRequest<User>(entityName: "User")fetchReq.predicate = NSPredicate(format: "name==%@", "b")do {let users = try context.fetch(fetchReq)for user in users {context.delete(user)}try context.save()} catch{print("error:\(error)")}
4.更多查询用法
- NSFetchRequest
– 初始化
//以User为例
//这里指定NSFetchRequestResultType为User,即NSManagedObject
let fetchReq = NSFetchRequest<User>(entityName: "User")
//返回类型还可以指定为NSNumber,NSDictionary,NSManagedObjectID
– 指定fetch限制
属性 | 含义 |
---|---|
predicate | 指定predicate |
fetchLimit | 提取数量 |
fetchOffset | 跳过多少开始获取 |
fetchBatchSize | 批量大小 |
affectedStores | 指定特定的sqlite |
//获取name为"a",从第2个开始,的3个User
let fetchReq = NSFetchRequest<User>(entityName: "User")
fetchReq.predicate = NSPredicate(format: "name == %@","a")
fetchReq.fetchLimit = 3
fetchReq.fetchOffset = 2
- 结果排序
//按name升序,name相同时按id降序
fetchReq.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true),NSSortDescriptor(key: "id", ascending: false)]
//可以自定义比较器实现自定义排序
init(key: String?, ascending: Bool, comparator: Comparator)
- fetch指定字段和Distinct
//返回特定的字段
//例只返回所有user的name,注意返回类型为NSDictionary,.dictionaryResultType
let fetchReq = NSFetchRequest<NSDictionary>(entityName: "User")
fetchReq.resultType = .dictionaryResultType
fetchReq.propertiesToFetch = ["name"]//返回唯一值,这里的唯一值是指propertiesToFetch中指定的所有字段相同的记录
fetchReq.returnsDistinctResults = true
//
- GroupBy和having
参考:https://developer.apple.com/documentation/foundation/nsexpression/1413747-init
//以name分组,并得到每组的数量
//select count(*),name from user group by name
let countExp = NSExpressionDescription()countExp.name = "count"countExp.expression = NSExpression(forFunction: "count:", arguments: [NSExpression(forKeyPath: "name")])fetchReq.propertiesToFetch = ["name",countExp]fetchReq.propertiesToGroupBy = ["name"]
//having count>=2
//参考:https://stackoverflow.com/questions/23116629/is-it-possible-to-use-a-group-by-count-in-the-havingpredicate-for-a-coredata-fet
fetchReq.havingPredicate = NSPredicate(format: "%@ >=2", NSExpression(forVariable: "count"))
Predicate编程
1.创建Predicate
- 使用格式化字符串创建
//name = b
NSPredicate(format: "name==%@", "b")
//name 以 b开头
//不使用参数,需要用\转义
NSPredicate(format: "name like \"b*\"")//不能像下面这样使用
NSPredicate(format: "name like %@*","b")//这样会格式化为name like "b"*
//正确的使用方法为
NSPredicate(format:"name like %@","b*")//如果属性也是动态的,则需要使用%K
NSPredicate(format:"%K like %@","name","b*")
- 直接使用代码创建
这样创建书写代码很多,但很容易懂
//例:创建表达式 id>=5 and id<8//先创建id>=5表达式:这是个比较类型的表达式所以用NSComparisonPredicate,leftExpression是表达式左边的内容id,这是个属性字段,需要用forKeyPath来创建,rightExpression是表达式右边的内容5,是个常量,用forConstantValue,modifier为direct直接比较,type为greaterThanOrEqualTo大于等于,options为额外的选项,比如.caseInsensitive忽略大小写,这里用.normalized为没有额外的选项.
let greaterThanOrEqualTo = NSComparisonPredicate(leftExpression: NSExpression(forKeyPath: "id"), rightExpression: NSExpression(forConstantValue: 5), modifier: .direct, type: .greaterThanOrEqualTo, options: .normalized)
//创建id<8表达式
let lessThan = NSComparisonPredicate(leftExpression: NSExpression(forKeyPath: "id"), rightExpression: NSExpression(forConstantValue: 8), modifier: .direct, type: .lessThan, options: .normalized)
//NSCompoundPredicate组合上面两个表达式,andPredicateWithSubpredicates表示用And连接
fetchReq.predicate =NSCompoundPredicate(andPredicateWithSubpredicates: [greaterThanOrEqualTo,lessThan])
- 从Predicate模板创建
//定义模板,$符号的变量是需要替换的变量
let template = NSPredicate(format: "name like $name")
//使用模板
//用b*代替$name
fetchReq.predicate = template.withSubstitutionVariables(["name":"b*"])
2.使用Predicate
- 评估evalute
let predicate = NSPredicate(format: "name like %@", "a*")
print(predicate.evaluate(with: ["name":"abc"]))//true
- 过滤数组
print(NSArray(array: ["abc","acd","bcd"]).filtered(using: NSPredicate(format: "SELF like %@", "a*")))
//[abc, acd]
3.字符串语法
符号 | 解释 | 例子 |
---|---|---|
%@ | 对象值(字符串,数字,日期等) | NSPredicate(format: “name like %@ and id==%@”,“a*”,NSNumber(2)) |
%K | key路径 | NSPredicate(format: “%K like %@”,“name”,“b*”) |
=,== | ||
>= | ||
<= | ||
> | ||
< | ||
!= | ||
BETWEEN | 位于区间 | NSPredicate(format: “id BETWEEN {%d,%d}”,2,5) |
AND,&& | ||
OR,|| | ||
NOT ,! | ||
[c] | 不区分大小写 | NSPredicate(format: “name BEGINSWITH[c] %@”,“B”) |
BEGINSWITH | 字符串以什么开头 | |
CONTAINS | 包含 | |
ENDWITH | 以什么结尾 | |
LIKE | 简单匹配,?一个字符,*0个或多个 | |
MATCHES | 正则表达式匹配 | |
IN | 在集合中 | NSPredicate(format: “name IN %@”,[“g”,“h”]) |
FALSE,NO | false | |
TRUE,YES | true | |
SELF | 要评估的对象本身 |
多线程
1.异步请求
NSAsynchronousFetchRequest
let fetchReq = NSFetchRequest<User>(entityName: "User")
let asyncReq = NSAsynchronousFetchRequest(fetchRequest: fetchReq) { result inprint(result.finalResult)
}
2.后台任务
unFinished
//todo:先看UI相关内容,再来更新这里
//新建任务上下文
let taskContext = container.newBackgroundContext()
//在任务上下文中执行IO操作
taskContainer.performAndWait{//...
}
//任务context的结果合并到viewContext
container.viewContext.automaticallyMergesChangesFromParent = true
批量处理
1.批量更新
NSBatchUpdateRequest
直接
批量更新数据,无需
先把数据查询出来到内存
//把id>3的所有记录的name改为hhh
let bur = NSBatchUpdateRequest(entityName: "User")bur.propertiesToUpdate = ["name":"hhh"]bur.predicate = NSPredicate(format: "id > 3")bur.includesSubentities = truebur.resultType = .updatedObjectsCountResultTypedo {let result = try context.execute(bur) as! NSBatchUpdateResultprint(result.result)} catch {print("error:\(error)")}
//返回类型有3种
//1.statusOnlyResultType只返回状态码,1为成功
//2.updatedObjectIDsResultType,返回更新了的objectId
//3.updatedObjectsCountResultType,返回更新了的记录数量
2.批量删除
与批量更新概念类似,初始化有一些区别
//1.创建批量删除请求,两种方式,
//第一种,通过构造查询请求,放入批量删除请求中,这样也是直接删除的,没有将查询请求的结果放入内存
init(fetchRequest: NSFetchRequest<NSFetchRequestResult>)
//第二种,放入需要删除的managedObjectId数组
init(objectIDs: [NSManagedObjectID])//2.配置返回类型,与批量查询类似,3种返回类型
batchDeleteReq.resultType
3.批量插入
let bir = NSBatchInsertRequest(entityName: "User", objects: [["id":10,"name":"P"],["id":11,"name":"Q"]])bir.resultType = .statusOnlydo {let result = try context.execute(bir) as! NSBatchInsertResultprint(result.result)} catch {print("error:\(error)")}
【ios笔记】CoreData相关推荐
- ios技术篇-CoreData
ios技术篇-CoreData 上一篇: iOS技术篇-CocoaPods 目录 下一篇:
- IOS笔记CALayer的position和anchorPoint
IOS笔记CALayer的position和anchorPoint CALayer有2个非常重要的属性:position和anchorPoint @property CGPoint position; ...
- iOS的CoreData技术笔记
本文字数:5914字 预计阅读时间:28分钟 为什么写这篇文章 最近因为新项目想用到数据持久化,本来这是很简单的事情,复杂数据一般直接SQLite就可以解决了. 但是一直以来使用SQLite确实存在要 ...
- iOS开发 CoreData的简单使用
CoreData介绍 CoreData是一门功能强大的数据持久化技术,位于SQLite数据库之上,它避免了SQL的复杂性,能让我们以更自然的方式与数据库进行交互.CoreData提供数据--OC对象映 ...
- iOS: 转载CoreData数据库框架
iphone-CoreData的使用详解 一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在M ...
- iOS之coreData
简单说明 coreData是苹果提供的数据本地化的解决方案中的一种,实质还是提供数据库去存储数据,只是在coreData中不需要程序员手动创建数据库文件,由coreData自动创建. coreData ...
- IOS笔记 本地化多语言支持
1.在Supporting Files文件夹右键,NewFile- -> iOS -> Resources -> String Files,命名为Localizable.string ...
- Xamarin开发IOS笔记:切换输入法时输入框被遮住
在进行IOS开发的过程中,出现类似微信朋友圈的交互界面,当用户遇到感兴趣的内容可以进行评论.为了方便评论输入,当出现评论输入框的时候自动将评论输入框移动至键盘的上方,这样方便边输入边查看. 当用户隐藏 ...
- ios笔记-单例文字代码详解
单例设计模式是ios开发中几大设计模式之一,每个项目中必有单例.下面我用文字加代码的方式讲一下单例模式. 1.我们简单的创建一个单例类 声明文件 #import <Foundation/Foun ...
最新文章
- 10 万开发者都知道的部署方式,你居然不知道!?(内含悬赏活动)
- python PyQt5 QLabel()(可以用来显示文字、图片或作为放置一些控件提示信息的容器)
- vtk鼠标不交互_vtk 各种不同的鼠标交互方式
- [代码整洁]自我感悟
- java类sample是公共的_应在名samle.java的文件_Andoid NDK编程 1 - 注册native函数
- cv2.imread读取图像结果none_python cv2.imread 读取中文路径的图片返回为None的问题
- 前端初级html\css知识点总结
- 调查显示:被黑过的公司难以找到投资
- GDataDate 的本地时间转换
- OpenCV——Sobel和拉普拉斯变换
- 微型计算机中的存储容量1TB等于,自考计算机应用基础_通关宝典
- oracle官网下载plsql,Oracle、OracleClient、PLSQL下载安装配置(64位)
- 艾默生Ev3100变频器源码,汇编语言的。电梯变频器
- PicGo 安装及配置
- X15 - 999、马克思主义基本原理概论、03709
- Python练习:贪吃蛇
- 利用集电极负反馈到基极,以及添加电阻的方法增加中间级放大器的稳定性方法
- 康奈尔大学计算机硕士要求,康奈尔大学计算机硕士
- 最值得珍藏的420个生活小窍门
- wden小波滤波函数