文章目录

  • 参考
  • 概念
    • 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

  • 帮助contextpersistentStore(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相关推荐

  1. ios技术篇-CoreData

    ios技术篇-CoreData 上一篇: iOS技术篇-CocoaPods       目录        下一篇:

  2. IOS笔记CALayer的position和anchorPoint

    IOS笔记CALayer的position和anchorPoint CALayer有2个非常重要的属性:position和anchorPoint @property CGPoint position; ...

  3. iOS的CoreData技术笔记

    本文字数:5914字 预计阅读时间:28分钟 为什么写这篇文章 最近因为新项目想用到数据持久化,本来这是很简单的事情,复杂数据一般直接SQLite就可以解决了. 但是一直以来使用SQLite确实存在要 ...

  4. iOS开发 CoreData的简单使用

    CoreData介绍 CoreData是一门功能强大的数据持久化技术,位于SQLite数据库之上,它避免了SQL的复杂性,能让我们以更自然的方式与数据库进行交互.CoreData提供数据--OC对象映 ...

  5. iOS: 转载CoreData数据库框架

    iphone-CoreData的使用详解 一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在M ...

  6. iOS之coreData

    简单说明 coreData是苹果提供的数据本地化的解决方案中的一种,实质还是提供数据库去存储数据,只是在coreData中不需要程序员手动创建数据库文件,由coreData自动创建. coreData ...

  7. IOS笔记 本地化多语言支持

    1.在Supporting Files文件夹右键,NewFile- -> iOS -> Resources -> String Files,命名为Localizable.string ...

  8. Xamarin开发IOS笔记:切换输入法时输入框被遮住

    在进行IOS开发的过程中,出现类似微信朋友圈的交互界面,当用户遇到感兴趣的内容可以进行评论.为了方便评论输入,当出现评论输入框的时候自动将评论输入框移动至键盘的上方,这样方便边输入边查看. 当用户隐藏 ...

  9. ios笔记-单例文字代码详解

    单例设计模式是ios开发中几大设计模式之一,每个项目中必有单例.下面我用文字加代码的方式讲一下单例模式. 1.我们简单的创建一个单例类 声明文件 #import <Foundation/Foun ...

最新文章

  1. 10 万开发者都知道的部署方式,你居然不知道!?(内含悬赏活动)
  2. python PyQt5 QLabel()(可以用来显示文字、图片或作为放置一些控件提示信息的容器)
  3. vtk鼠标不交互_vtk 各种不同的鼠标交互方式
  4. [代码整洁]自我感悟
  5. java类sample是公共的_应在名samle.java的文件_Andoid NDK编程 1 - 注册native函数
  6. cv2.imread读取图像结果none_python cv2.imread 读取中文路径的图片返回为None的问题
  7. 前端初级html\css知识点总结
  8. 调查显示:被黑过的公司难以找到投资
  9. GDataDate 的本地时间转换
  10. OpenCV——Sobel和拉普拉斯变换
  11. 微型计算机中的存储容量1TB等于,自考计算机应用基础_通关宝典
  12. oracle官网下载plsql,Oracle、OracleClient、PLSQL下载安装配置(64位)
  13. 艾默生Ev3100变频器源码,汇编语言的。电梯变频器
  14. PicGo 安装及配置
  15. X15 - 999、马克思主义基本原理概论、03709
  16. Python练习:贪吃蛇
  17. 利用集电极负反馈到基极,以及添加电阻的方法增加中间级放大器的稳定性方法
  18. 康奈尔大学计算机硕士要求,康奈尔大学计算机硕士
  19. 最值得珍藏的420个生活小窍门
  20. wden小波滤波函数

热门文章

  1. 泰山OFFICE技术讲座:使用字体斜体的四种情形
  2. JavaWeb项目结构使用Vue项目
  3. 配置计算机失败 备份,win10系统备份失败提示0x80070422的设置技巧
  4. 欢迎加入CSDN React社区
  5. 【Linux】CentOS安装Chrome浏览器
  6. Android 创建桌面快捷图标
  7. 王者荣耀鸿蒙抽奖,王者荣耀鸿运抽奖奖励有哪些 鸿运6+1抽奖概率一览
  8. 赚钱 36 计 - 第二十计:明星计
  9. 云数据库(RDS)- ECS自建MySQL和阿里云RDS的区别
  10. 考研前辈的后悔清单,你中了多少条?