CoreData
- 怎么在SwiftUI中运用CoreData
- 在SwiftUI中怎么装备Core Data
- 怎么从SwiftUI视图拜访中心数据管理目标Context
- 怎么运用@FetchRequest创立一个中心数据获取恳求
- 怎么运用predicate过滤CoreData的fetchRequests
- 怎么从SwiftUI视图增加CoreData目标
- 怎么从SwiftUI视图中删去CoreData目标
- 怎么约束获取FetchRequest中的item数量
- 怎么在SwiftUI中运用NSUserActivity
概述
文章首要共享SwiftUI Modifier的学习进程,将运用事例的办法进行阐明。内容深入浅出,CoreData部分调试,不过测试代码是齐全的。假如想要运转成果,能够移步Github下载code -> github事例链接
1、怎么在SwiftUI中运用CoreData
SwiftUI和CoreData
作为Apple软件渠道的其间两个重要组成部分,有很好的协同能力,SwiftUI有特点包装器、环境支持等等,这些都是为了保证能以最小的费事将Core Data集成到SwiftUI的App中。在SwiftUI之前,在架构角度来看,运用Core Data的办法如下:
- Apple主张在AppDelegate的级别创立容器,然后根据需要return
- 一部分人喜爱运用Manager Classes
- 还有一部分人喜爱彻底笼统Core Data,以便利彻底转移到Realm或其他可选项
SwiftUI与Core Data的集成是不同的,在发动时,需要创立Core Data容器,然后将其保管目标注入到环境中,然后直接在那里履行Request。以下是四个特定的功能,能够帮你理解我的意思:
- NSManagedObject遵守ObservableObject协议,这代表能够将任何目标绑定到用户界面。
- 环境中有一个
managedObjectContent
的key,用于存储Core Data保管目标的上下文。 - 然后Xcode的模板将这个context注入到初始的内容视图中。
- 有一个
@FetchRequest
的特点包装器,它运用环境的保管目标上下文来获取request
因此,在应用发动时创立一个保管目标上下文,将其附加到视图的环境中,然后运用@FetchRequest加载数据供App运用。
2、在SwiftUI中怎么装备Core Data
假如创立一个新项目,运用的是SwiftUI并需要运用Core Data,Xcode的装备分为四步:
- 创立一个空的项目模板,通常以你的项目命名(FFModifier.xcdatamodeld),和一个示例装备
- 增加一个Persistence.swift文件,将Core Data整齐的封装在这个地方。
- 运用managedObjectContext将上下文注入初始ContentView的environment中。
- 创立在ContentView中创立、读取和删去示例数据的示例代码。
这是供给了在SwiftUI中运用CoreData获取request的完好能力。
2.1、创立Main.xcdatamodeld
经过cmd+N来创立一个新文件,然后选择Data Model来创立一个Core Data模型。这个模型的姓名很重要,因为要在代码中引证,我这儿命名为“Main”。一旦创立了model,那么就能够在任何想要运用的方位创立实例。
2.2、创立ProgrammingLanguage的实例
打开xcdatamodeld文件并创立一个名为ProgrammingLanguage
的实例,我创立了两个字符串特点:“name”和“creator”。你能够根据你的需求创立想要的任何特点了。
2.3、创立PersistenceController单例
需要一个地方来加载和管理Core Data装备,Apple的模版经过一个PersistenceController
单例完成。首要做的工作是让Core Data发动并运转,同时也为SwiftUI供给与来Contenxts的能力。
import CoreData
struct PersistenceController {
//创立单例
static let shared = PersistenceController()
//Core Data
let container: NSPersistentContainer
//SwiftUI预览装备
static var preview: PersistenceController = {
let controller = PersistenceController(inMemory: true)
//创立10个example
for i in 0..<100 {
let language = ProgrammingLanguage(context: controller.container.viewContext)
language.name = "Example Language \(i)"
language.creator = "A.Programmer \(i)"
}
return controller
}()
//加载Core Data初始化器,将运用内存存储设定为可选值
init(inMemory: Bool = false) {
//将Main更改为你自己的名
container = NSPersistentContainer(name: "Main")
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(filePath: "/dev/null")
}
container.loadPersistentStores { descroption, error in
if let error = error {
fatalError("BBLv Error: \(error.localizedDescription)")
}
}
}
//向PersistenceController类增加save办法,以便它查看context是否更改。
func save() {
let context = container.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
print("save error: \(error.localizedDescription)")
}
}
}
}
2.4、将Core Data容器的保管目标context注入到SwiftUI环境中
let persistenceController = PersistenceController.shared
2.5、scenePhase监听App状况
最终一步是可选的,但主张运用,来保证数据完好,针对的场景是当App状况切换为后台时,应该调用save()
办法,以便Core Data来保存你的更改,在SwiftUI中,经过增加一个特点到App来监听场景。
@Environment(\.scenePhase) var scenePhase
2.6、结合起来的代码
这段代码写在FFModifierApp中,APP的main入口,因为做了许多其他的比方也用到了这个入口,目前这儿代码比较多,这是我整理的只要关于CoreData部分的代码。
@main
struct FFModifierApp: App {
//将Core Data容器的保管目标context注入到SwiftUI环境中,这儿运用perview运用的是假数据,
//假如真实情况下,运用单例进行初始化(PersistenceController.shared)
let persistenceController = PersistenceController.preview
//最终一步是可选的,但主张运用,来保证数据完好,针对的场景是当App状况切换为后台时,
//应该调用save()办法,以便Core Data来保存你的更改,在SwiftUI中,经过增加一个特点到App来监听场景。
@Environment(\.scenePhase) var scenePhase
var body: some Scene {
WindowGroup {
FFCoreDataFetchRequest()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
.onChange(of: scenePhase) {
persistenceController.save()
}
}
}
在上面的PersistenceController.swift类中我选择将数据保存在内存中了,所以该代码的内存存储部分很重要,因为Core Data装备为将信息保存到内存而不是磁盘是,这代表着Core Data中的数据被定义为暂时数据,在程序关闭时会被清理。
3、怎么从SwiftUI视图拜访中心数据管理目标Context
中心代码为@Environment(\.managedObjectContext) var managedObjectContext
,在每一个想要运用CoreData的上下文内容上都要运用这个环境变量。下面的比方仅代表着FFCoreDataManagged想要运用数据。可是啥也没干。
struct FFCoreDataManagged: View {
//将context作为环境变量传递给ContentView(我这儿是FFCoreDataManagged),
//在此视图中增加一个@Environment特点来读取保管目标上下文。
@Environment(\.managedObjectContext) var managedObjectContext
var body: some View {
Text("Hello, World!")
}
}
4、怎么运用@FetchRequest创立一个中心数据获取恳求
FetchRequest能够加载符合指定的条件的Core Data成果,并且SwiftUI能够将这些成果直接绑定到用户界面。创立fetchRequest需要两条信息:
- 要查询的实体
- 以及确认回来成果次序的排序描述符。
struct FFCoreDataFetchRequest: View {
@Environment(\.managedObjectContext) var managedObjectContext
// SortDescriptors参数是一个数组,所以能够供给尽可能多的排序选项
@FetchRequest(sortDescriptors: []) var languages: FetchedResults<ProgrammingLanguage>
var body: some View {
List(languages) { language in
Text(language.name ?? "UnKnown")
}
}
}
调试成果
看似简略的代码就成功获得了数据,其实是上面许多过程后的成果
5、怎么运用predicate过滤CoreData的fetchRequests
CoreData的fetchRequest中能够运用Predicates,就像在UIKit中,所有这些都是通向你的@FetchRequest
特点包装器供给一个predicate来完成的。
struct FFCoreDataFetchRequestsFilter: View {
@Environment(\.managedObjectContext) var managedObjectContext
//创立predicate
@FetchRequest(
sortDescriptors: [],
predicate: NSPredicate(format: "name == %@", "Python")
) var languages: FetchedResults<ProgrammingLanguage>
//目前@FetchRequest运用的是规范的CoreData的Predicate,也能够创立复合Predicate
var body: some View {
List(languages) { language in
Text(language.name ?? "UnKnown")
}
}
}
6、怎么从SwiftUI视图增加CoreData目标
在SwiftUI中保存core data目标的工作办法与在SwiftUI之外的工作往事彻底相同,拜访保管目标的context
,在该上下文中创立你的类型的实例,然后在准备好时保存context。
struct FFCoreDataAddObjects: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(sortDescriptors: []) var languages: FetchedResults<ProgrammingLanguage>
var body: some View {
//创立实例
Button("Insert Example Languate") {
let language = ProgrammingLanguage(context: managedObjectContext)
language.name = "Python"
language.creator = "Guido van Rossum"
PersistenceController.shared.save()
}
//在增加一组目标之后,程序会多一组目标。
List(languages) { language in
Text(language.name ?? "UnKnown")
}
}
}
调试成果
7、怎么从SwiftUI视图中删去CoreData目标
在SwiftUI中删去CoreData目标与在UIKit中删去他们根本相同,虽然需要越过一些特殊的过程才能与SwiftUI视图集成。
struct FFCoreDataDeleteObjects: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(
sortDescriptors: []
) var languages: FetchedResults<ProgrammingLanguage>
var body: some View {
//不管在哪里显示数据,都向SwiftUI视图增加onDelete修饰符。
List {
ForEach(languages) { language in
Text("Creator: \(language.creator ?? "Anonymous")")
}
.onDelete(perform: { indexSet in
removelanguages(at: indexSet)
})
}
.toolbar(content: {
EditButton()
})
}
func removelanguages(at offsets: IndexSet) {
for index in offsets {
let language = languages[index]
managedObjectContext.delete(language)
}
PersistenceController.shared.save()
}
}
调试成果
8、怎么约束获取FetchRequest中的item数量
SwiftUI的@FetchRequest特点包装器非常合适对Object宣布简略request,供给排序和过滤功能。可是,假如想调整回来item的数量,那么需要额外设置
struct FFCoreDataLimit: View {
@Environment(\.managedObjectContext) var managedObjectContext
//创立@FetchRequest
@FetchRequest var languages: FetchedResults<ProgrammingLanguage>
init() {
let request: NSFetchRequest<ProgrammingLanguage> = ProgrammingLanguage.fetchRequest()
request.sortDescriptors = [
NSSortDescriptor(keyPath: \ProgrammingLanguage.name, ascending: true)
]
request.fetchLimit = 10
_languages = FetchRequest(fetchRequest: request)
}
var body: some View {
List(languages) { language in
Text(language.name ?? "UnKnown")
}
}
}
9、怎么在SwiftUI中运用NSUserActivity
SwiftUI有一个专用的onContinueUserActivity()
修饰符,能够捕获各种NSUserActivity类型,比方来自网络的点击、来自第三方或者Siri发动等等。在AppDelegate中运用application(_:continue:restorationHandler:)
处理过这个问题,但SwiftUI办法更简略的处理这个问题。要完成这个需求,首先要创立一个函数并承受参数NSUserActivity,可是,不需要在App结构体中履行此操作。
func handleWechatLogin(_ userActivity: NSUserActivity) {
if let id = userActivity.userInfo?["targetContentIdentifier"] {
print("Found identifier \(id)")
}
}
运用办法
var body: some Scene {
WindowGroup {
FFCoreDataDeleteObjects()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.onContinueUserActivity("targetContentIdentifier", perform: { userActivity in
handleWechatLogin(userActivity)
})
}
.onChange(of: scenePhase) {
persistenceController.save()
}
}