版本记录
版本号 | 时间 |
---|---|
V1.0 | 2022.05.30 星期一 |
前言
数据的持久化存储是移动端不可避免的一个问题,很多时候的业务逻辑都需要我们进行本地化存储解决和完成,我们可以采用很多持久化存储方案,比如说
plist
文件(属性列表)、preference
(偏好设置)、NSKeyedArchiver
(归档)、SQLite 3
、CoreData
,这里基本上我们都用过。这几种方案各有优缺点,其中,CoreData是苹果极力推荐我们使用的一种方式,我已经将它分离出去一个专题进行说明讲解。这个专题主要就是针对另外几种数据持久化存储方案而设立。
1. 数据持久化方案解析(一) —— 一个简单的基于SQLite持久化方案示例(一)
2. 数据持久化方案解析(二) —— 一个简单的基于SQLite持久化方案示例(二)
3. 数据持久化方案解析(三) —— 基于NSCoding的持久化存储(一)
4. 数据持久化方案解析(四) —— 基于NSCoding的持久化存储(二)
5. 数据持久化方案解析(五) —— 基于Realm的持久化存储(一)
6. 数据持久化方案解析(六) —— 基于Realm的持久化存储(二)
7. 数据持久化方案解析(七) —— 基于Realm的持久化存储(三)
8. 数据持久化方案解析(八) —— UIDocument的数据存储(一)
9. 数据持久化方案解析(九) —— UIDocument的数据存储(二)
10. 数据持久化方案解析(十) —— UIDocument的数据存储(三)
11. 数据持久化方案解析(十一) —— 基于Core Data 和 SwiftUI的数据存储示例(一)
12. 数据持久化方案解析(十二) —— 基于Core Data 和 SwiftUI的数据存储示例(二)
13. 数据持久化方案解析(十三) —— 基于Unit Testing的Core Data测试(一)
14. 数据持久化方案解析(十四) —— 基于Unit Testing的Core Data测试(二)
15. 数据持久化方案解析(十五) —— 基于Realm和SwiftUI的数据持久化简单示例(一)
16. 数据持久化方案解析(十六) —— 基于Realm和SwiftUI的数据持久化简单示例(二)
17. 数据持久化方案解析(十七) —— 基于NSPersistentCloudKitContainer的Core Data和CloudKit的集成示例(一)
18. 数据持久化方案解析(十八) —— 基于NSPersistentCloudKitContainer的Core Data和CloudKit的集成示例(二)
19. 数据持久化方案解析(十九) —— 基于批插入和存储历史等高效CoreData使用示例(一)
20. 数据持久化方案解析(二十) —— 基于批插入和存储历史等高效CoreData使用示例(二)
开始
首先看下主要内容:
本文主要学习了
SwiftUI App
中Core Data
和CloudKit
之间的数据共享,内容来自翻译。
接着看下写作环境
Swift 5.5, iOS 15, Xcode 13
下面就是正文了。
在 2019
年全球开发者大会(WWDC)
上,Apple 推出了只需几个步骤即可将 CloudKit
功能添加到由 Core-Data
支持的应用程序的功能。理论上,您只需要三个步骤。首先,将您的容器类型更新为 NSPersistentCloudKitContainer
。其次,在您的应用中启用 iCloud
功能。第三,创建一个 iCloud
容器,在 iCloud
中托管您的数据。
完成这些步骤后,应用程序中的数据就会“自动”与 iCloud
同步。很好吧!但是,这样做的一个限制是您无法轻松地与其他人共享您的数据以做出贡献。在 WWDC 2021
上,Apple
推出了一种让您与其他 iCloud
用户共享数据并邀请他们为您的应用程序数据做出贡献的方法。
在本教程中,您将探索如何更新现有的 Core Data
和 CloudKit
应用程序以共享数据并邀请用户为您的应用程序中的数据做出贡献。
注意:您需要满足以下先决条件才能完成本教程。
- 付费开发者帐户——使用
CloudKit
。- 两个独立的
iCloud
帐户 — 启动共享过程。- 至少一台真实设备——发送和接受分享邀请。另外,更改共享权限,因为它在模拟器上无法正常工作。
打开启动项目。 当您检查起始代码时,您会发现起始项目是一个基本的 Core Data
应用程序,具有 CRUD
(创建、读取、更新、删除)功能。
在项目的设置中,将签名团队设置为您的付费开发者帐户。
构建并运行。 您会看到一个带有空白状态消息和一个按钮的旅行日志屏幕。
点击Add Destination
按钮。 这会将您带到一个屏幕以添加您最近访问的目的地。 在此屏幕上,您可以提供目的地的标题、描述和照片。
添加目的地后,您将在主屏幕上看到它,如下所示。
要删除目的地,请向左滑动以显示删除按钮。点击此按钮会从您的旅行日志中删除一个目的地。
要编辑或更新标题或说明,请点击目标单元格以查看详细信息屏幕。在此屏幕中,您可以执行一些操作。
右上角是编辑按钮,它提供了一个模式来编辑目的地的标题和描述。还有一个 share action
现在什么都不做。您将在本教程中构建此操作。
Types of CloudKit Databases
在开始启用 CloudKit
同步之前,您首先需要了解可以存储数据的三种类型的数据库。
-
Public:这里存储的数据是公开的,每个用户,无论他们是否登录
iCloud
帐户,都可以读取它。对于本教程,您将在此数据库中存储数据。 - Private:此处存储的数据是与当前登录用户关联的私有数据。
- Shared:此处存储的数据在其他登录用户的私有数据库之间共享。当您稍后开始共享过程时,如果其他用户与您共享记录,您将开始看到此处填充的数据。
Enabling CloudKit Syncing
准备共享数据的下一步是启用将数据存储在 iCloud
中。当您创建目的地时,数据将通过 Core Data
在您的应用程序中本地保存。
在 Signing & Capabilities
部分,添加 iCloud
功能。您需要确保此时已设置唯一的bundle identifier
。然后,选中 CloudKit
复选框以启用该功能。
下一步是创建数据所在的容器。在 iCloud
部分,点击容器下方的 +
按钮以添加自定义容器。 在出现的窗口中,输入容器的名称。 一般准则是使用 com.company_name.bundle_identifier
。 Xcode 在容器名称前加上 iCloud
。
最后一步是添加Background Modes
功能并启用Remote Notifications
。 这允许 CloudKit
在 iCloud
中的数据发生更改并且您的设备需要更新以反映此更改时向您的设备发送静默推送通知。
现在您已经配置了 CloudKit
,请在您将要测试的设备上登录您的 iCloud
帐户。
启动模拟器。 在主屏幕上,打开设置。 登录您的 Apple ID
。
构建并运行。 添加目的地。
最后,前往 CloudKit Console,以便您可以验证您的数据。
1. CloudKit Console Dashboard
通过 CloudKit
存储数据时,CloudKit
控制台允许您与相关数据进行交互并执行其他一些功能,例如查看日志。 登录控制台后,打开 CloudKit Database
。
进入此部分后,您需要指定要查看的容器。 在屏幕顶部,选择下拉菜单并单击您之前从 Xcode 创建的容器container
。
在数据部分下方,单击Records
。 选择Private Database
。 这是数据写入的默认数据库。
如果您尝试将记录类型选择为 CD_Destination
并从此处查询记录,您会收到一条错误消息,Field recordName isn’t marked queryable
。 现在,您将解决此错误。
在Schema
部分下,选择Indexes
。 选择 CD_Destination
。 这是您在Core Data
中的Destination entity
。 CloudKit
为您的实体添加 CD
前缀,以将它们与传统的 CloudKit
记录区分开来。
单击Add Basic Index
。 从列表中选择 recordName
并确保索引类型为 Queryable
。 保存更改。
现在您已使您的记录可查询,请单击数据部分下的Records
。 选择Private Database
。 将记录类型指定为 CD_Destination
。 将所选区域从 defaultZone
更新为自动生成的 com.apple.coredata.cloudkit.zone
。
单击Query Records
以查看您之前在应用程序中创建的记录的列表! 最令人惊奇的是,由于您的数据现在已在 iCloud
中同步,您可以在登录到同一个 iCloud
帐户的完全不同的设备上运行您的应用程序并查看您的所有数据!
Updating NSPersistentCloudKitContainer to Prepare for Share
此时,您的应用程序可以将您的更改本地保存在设备上,同时还可以将它们与 iCloud
中的私有数据库同步。 但是,为了允许其他用户与这些数据进行交互,您需要更新您的 NSPersistentCloudKitContainer
。 打开 CoreDataStack.swift
。 该类包含与 Core Data
交互所需的所有必要方法和属性。 要开始共享过程,请将以下代码添加到您的 persistentContainer
的 // TODO: 1
注释下方:
let sharedStoreURL = storesURL?.appendingPathComponent("shared.sqlite")
guard let sharedStoreDescription = privateStoreDescription
.copy() as? NSPersistentStoreDescription else {
fatalError(
"Copying the private store description returned an unexpected value."
)
}
sharedStoreDescription.url = sharedStoreURL
此代码将共享数据库配置为存储与您共享的记录。 为此,您复制您的 privateStoreDescription
并将其 URL
更新为 sharedStoreURL
。
接下来,在 // TODO: 2
注释下添加以下代码:
guard let containerIdentifier = privateStoreDescription
.cloudKitContainerOptions?.containerIdentifier else {
fatalError("Unable to get containerIdentifier")
}
let sharedStoreOptions = NSPersistentCloudKitContainerOptions(
containerIdentifier: containerIdentifier
)
sharedStoreOptions.databaseScope = .shared
sharedStoreDescription.cloudKitContainerOptions = sharedStoreOptions
此代码使用您的私有商店描述中的标识符创建 NSPersistentContainerCloudKitContainerOptions
。 除此之外,您将 databaseScope
设置为 .shared
。 最后一步是为您创建的 sharedStoreDescription
设置 cloudKitContainerOptions
属性。
接下来,在 // TODO: 3
注释下方添加以下代码:
container.persistentStoreDescriptions.append(sharedStoreDescription)
此代码将您共享的 NSPersistentStoreDescription
添加到容器中。
最后并在 // TODO: 4
下,替换:
container.loadPersistentStores { _, error in
if let error = error as NSError? {
fatalError("Failed to load persistent stores: \(error)")
}
}
为
container.loadPersistentStores { loadedStoreDescription, error in
if let error = error as NSError? {
fatalError("Failed to load persistent stores: \(error)")
} else if let cloudKitContainerOptions = loadedStoreDescription
.cloudKitContainerOptions {
guard let loadedStoreDescritionURL = loadedStoreDescription.url else {
return
}
if cloudKitContainerOptions.databaseScope == .private {
let privateStore = container.persistentStoreCoordinator
.persistentStore(for: loadedStoreDescritionURL)
self._privatePersistentStore = privateStore
} else if cloudKitContainerOptions.databaseScope == .shared {
let sharedStore = container.persistentStoreCoordinator
.persistentStore(for: loadedStoreDescritionURL)
self._sharedPersistentStore = sharedStore
}
}
}
上面的代码在加载时存储了对每个存储的引用。它检查 databaseScope
并确定它是private
还是shared
。然后,它根据范围设置persistent store
。
Presenting UICloudSharingController
UICloudSharingController 是一个视图控制器,它显示用于从 CloudKit
共享记录中添加和删除人员的标准屏幕。此控制器邀请其他用户为应用程序中的数据做出贡献。只有一个问题:这个控制器是一个 UIKit
控制器,而你的应用是 SwiftUI
。
解决方案在 CloudSharingController.swift
中。 CloudSharingView
符合协议 UIViewControllerRepresentable
并包装了 UIKit UICloudSharingController
以便您可以在 SwiftUI
中使用它。 CloudSharingView
具有三个属性:
- CKShare:您用于共享的记录类型。
- CKContainer:存储您的私有、共享或公共数据库的容器。
- Destination:包含您正在共享的数据的实体。
在 makeUIViewController(context:)
中,会发生以下操作。它:
- 1) 配置共享的标题。当
UICloudSharingController
呈现给用户时,他们必须有一些共享数据的上下文。在这种情况下,您使用目的地的标题。 - 2) 使用
share
和container
属性创建UICloudSharingController
。演示样式设置为.formSheet
,代理使用CloudSharingCoordinator
设置。这遵循UICloudSharingControllerDelegate
。此代理包含在共享发生某些操作时通知您的便捷方法,例如错误和共享状态。现在您已经了解CloudSharingView
的工作原理,是时候将它连接到您的共享按钮了。
现在,打开 DestinationDetailView.swift
。此视图包含共享按钮的逻辑。第一步是创建一个准备共享数据的方法。为此,iOS 15
引入了 share(_:to:)
。将以下代码添加到扩展块:
private func createShare(_ destination: Destination) async {
do {
let (_, share, _) =
try await stack.persistentContainer.share([destination], to: nil)
share[CKShare.SystemFieldKey.title] = destination.caption
self.share = share
} catch {
print("Failed to create share")
}
}
上面的代码调用 share(_:to:)
的异步版本来共享您选择的目的地。 如果没有错误,则设置共享的标题。 从这里,您存储对从 share
方法返回的 CKShare
的引用。 当您展示 CloudSharingView
时,您将使用默认共享。
现在您有了执行共享的方法,您需要在点击共享按钮时显示 CloudSharingView
。 在您这样做之前,请考虑一个小警告:只有尚未共享的对象才调用 share(_:to:)
。 要检查这一点,请添加一些代码来确定相关对象是否已共享。
回到 CoreDataStack.swift
,添加以下扩展:
extension CoreDataStack {
private func isShared(objectID: NSManagedObjectID) -> Bool {
var isShared = false
if let persistentStore = objectID.persistentStore {
if persistentStore == sharedPersistentStore {
isShared = true
} else {
let container = persistentContainer
do {
let shares = try container.fetchShares(matching: [objectID])
if shares.first != nil {
isShared = true
}
} catch {
print("Failed to fetch share for \(objectID): \(error)")
}
}
}
return isShared
}
}
此扩展包含与共享相关的代码。 该方法检查传入的 NSManagedObjectID
的 persistentStore
,看它是否是 sharedPersistentStore
。 如果是,则该对象已被共享。 否则,请使用 fetchShares(matching:)
查看您是否有与相关 objectID
匹配的对象。 如果匹配返回,则该对象已被共享。 一般来说,您将在视图中使用 NSManagedObject
。
将以下方法添加到您的扩展中:
func isShared(object: NSManagedObject) -> Bool {
isShared(objectID: object.objectID)
}
使用此代码,您可以确定目标是否已共享,然后采取适当的措施。
将以下代码添加到 CoreDataStack
:
var ckContainer: CKContainer {
let storeDescription = persistentContainer.persistentStoreDescriptions.first
guard let identifier = storeDescription?
.cloudKitContainerOptions?.containerIdentifier else {
fatalError("Unable to get container identifier")
}
return CKContainer(identifier: identifier)
}
在这里,您使用持久容器存储描述创建了 CKContainer
属性。
当您准备展示您的 CloudSharingView
时,您需要此属性,因为 CloudSharingView
的第二个参数是一个 CKContainer
。
使用此代码,导航回 DestinationDetailView.swift
以显示 CloudSharingView
。 为此,您需要一个 state
属性来控制 CloudSharingView
作为工作表的呈现。
首先,将以下属性添加到 DestinationDetailView
:
@State private var showShareSheet = false
其次,您需要在 List
中添加工作表修饰符以呈现 CloudSharingView
。 在现有的工作表修饰符上方添加以下代码:
.sheet(isPresented: $showShareSheet, content: {
if let share = share {
CloudSharingView(
share: share,
container: stack.ckContainer,
destination: destination
)
}
})
当布尔值为true
时,此代码使用 showShareSheet
呈现 CloudSharingView
。 要切换此布尔值,您需要更新共享按钮内的逻辑。
替换:
print("Share button tapped")
为
if !stack.isShared(object: destination) {
Task {
await createShare(destination)
}
}
showShareSheet = true
这个逻辑首先检查对象是否被共享。 如果未共享,则从目标对象创建共享。 完成该任务后,将显示 CloudSharingView
的 showShareSheet
设置为 true
。 您现在已准备好展示云共享视图并添加人员为您的日记做出贡献。
在真实设备上登录您的 iCloud
帐户。 构建并运行。 添加目的地。 在设备上运行的原因是向第二个 iCloud
帐户发送邀请。 最常见的选项是通过电子邮件或短信。
添加目的地后,点击destination
以查看 DestinationDetailView
。 在此处,点击右上角的Share
按钮。 选择您想要的交付方式并发送邀请。
注意:您也可以使用模拟器共享邀请。 打开您要共享的数据,然后点击共享按钮。 从这里,复制链接并使用模拟器中的
Safari
浏览器通过电子邮件发送。
Accepting Share Invitations
现在您已经向第二个用户发送了邀请,您需要将应用程序设置为接受邀请并将数据添加到共享存储中。 导航到 AppDelegate.swift
你会看到 SceneDelegate
是空的。 在这里,您将添加代码以接受共享。
第一步是实现UIKit scene
场景代理方法windowScene(_:userDidAcceptCloudKitShareWith:)
。 当用户点击之前共享的链接并接受邀请时,代理会调用此方法并启动应用程序。 将以下方法添加到 SceneDelegate
:
func windowScene(
_ windowScene: UIWindowScene,
userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata
) {
let shareStore = CoreDataStack.shared.sharedPersistentStore
let persistentContainer = CoreDataStack.shared.persistentContainer
persistentContainer.acceptShareInvitations(
from: [cloudKitShareMetadata], into: shareStore
) { _, error in
if let error = error {
print("acceptShareInvitation error :\(error)")
}
}
}
此代码首先获取对您在本教程开头创建的 sharedPersistentStore
的引用。 iOS 15
中的新功能是 acceptShareInvitations(from:into:completion:)
。 persistentContainer
调用此方法。 它接受共享并将必要的元数据添加到 sharedPersistentStore
中。 而已!
现在,是时候在第二台设备上构建和运行了,登录到第二个 iCloud
帐户。 如果您从真实设备发送邀请,那可以是模拟器。
当应用程序启动时,您会注意到共享日记条目没有显示。 这是因为您还没有接受邀请。 此时,如果您通过短信分享了邀请,请打开信息Messages
并点击邀请。
当对话框询问您是否要打开邀请时,选择Open。
您现在可以在第二台设备上看到共享条目。 很令人吃惊吧!
Fetching Shared Data
至此,您已经创建了一个日记条目并与其他用户共享。 一旦您在第二台设备上接受共享,它现在就是您在iCloud
中共享区域的一部分。 因此,当应用程序启动并且您与 iCloud
同步时,您在 iCloud
中的数据会与您的设备同步并自动显示。 但是,您没有任何关于共享的元数据。 最终目标不仅是显示共享条目,还要获取有关参与共享的人员的信息。
为此,您将实现 fetchShares(matching:)
。 当您需要确定一个对象是否为isShared
时,您已经实现了一次此方法。 打开 CoreDataStack.swift
并将以下代码添加到扩展中:
func getShare(_ destination: Destination) -> CKShare? {
guard isShared(object: destination) else { return nil }
guard let shareDictionary = try? persistentContainer.fetchShares(matching: [destination.objectID]),
let share = shareDictionary[destination.objectID] else {
print("Unable to get CKShare")
return nil
}
share[CKShare.SystemFieldKey.title] = destination.caption
return share
}
上面的代码执行以下操作:
- 检查对象是否共享。 如果它没有关联的共享记录,则无需继续。
- 使用
fetchShares(matching:)
,返回匹配的NSManagedObjectID
及其关联的CKShare
的字典。 - 从字典中提取
CKShare
。 - 使用
destination
的标题设置共享的标题。 - 返回
CKShare
。
要使用这个新方法,请打开 DestinationDetailView.swift
。 目标是在详细视图出现时为该对象获取关联的 CKShare
。 添加以下代码作为 List 的修饰符之一:
.onAppear(perform: {
self.share = stack.getShare(destination)
})
此代码使用 getShare(_:)
并检索 CKShare
。 您需要提取有关此共享参与者的信息。 使用此代码,在您的第二台设备上构建和运行。 点击共享对象以转到详细信息屏幕。 看到数据现在存在于Participants
部分的底部。
注意每个用户的角色和权限。一个用户显示为Owner
,另一个显示为Private User
,两个用户都具有Read-Write
权限。这意味着不仅所有者而且第二个用户都可以修改与他们共享的数据。
为了更改对这些数据的权限和访问权限,Apple
已经为您完成了所有繁重的工作。到您从中创建共享的第一台设备,因为您需要成为Owner
才能访问Share Options
。构建并运行,然后执行以下步骤:
- 1) 点击您要为其更新权限的条目。
- 2) 在详细信息屏幕中,点击
Share
操作。 - 3) 请注意
CloudSharingView
根据它所拥有的关于CKShare
的信息在新的上下文中启动。在此屏幕中,您可以全局更新权限或为特定参与者更新权限。选择Share Options
并将权限更新为仅查看(View only)
。有权访问此共享的每个人都只有读取(Read)
权限。
请注意,用户当前可以读取和写入正在修改权限的条目。
在更新权限的上下文中观察 CloudSharingView
。
看share options
。 将权限更改为View only
。
再次构建并运行。 更改会同步,具有更新权限的条目现在显示为Read-Only
。
1. Displaying Private Data Versus Shared Data
目前,当您启动该应用程序时,您日记中的条目看起来都一样。 区分私人记录与共享记录的唯一方法是点击详细信息并查看参与者列表中的角色。 要改进这一点,请返回 HomeView.swift
。 然后,替换以下代码:
VStack(alignment: .leading) {
Image(uiImage: UIImage(data: destination.image ?? Data()) ?? UIImage())
.resizable()
.scaledToFill()
Text(destination.caption)
.font(.title3)
.foregroundColor(.primary)
Text(destination.details)
.font(.callout)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
}
为
VStack(alignment: .leading) {
Image(uiImage: UIImage(data: destination.image ?? Data()) ?? UIImage())
.resizable()
.scaledToFill()
Text(destination.caption)
.font(.title3)
.foregroundColor(.primary)
Text(destination.details)
.font(.callout)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
if stack.isShared(object: destination) {
Image(systemName: "person.3.fill")
.resizable()
.scaledToFit()
.frame(width: 30)
}
}
此代码使用 isShared
来确定记录是否是共享的一部分。 构建并运行。 请注意,您的共享记录现在有一个图标,表明它已与其他用户共享。
Challenge Time
要进一步改进应用程序,请在允许编辑或删除记录等特定操作之前考虑用户的角色和权限。
1. Challenge One
在persistentContainer
上使用canUpdateRecord(forManagedObjectWith:)
和canDeleteRecord(forManagedObjectWith:)
,调整视图逻辑,使其考虑权限。
你能弄清楚吗? 请参阅以下解决方案:
打开
CoreDataStack.swift
。 在isShared(object:)
下,添加以下方法:func canEdit(object: NSManagedObject) -> Bool { return persistentContainer.canUpdateRecord( forManagedObjectWith: object.objectID ) } func canDelete(object: NSManagedObject) -> Bool { return persistentContainer.canDeleteRecord( forManagedObjectWith: object.objectID ) }
这些方法根据对象的权限返回一个布尔值。
接下来,打开
DestinationDetailView.swift
。 查找包含Text("Edit")
按钮的ToolBarItem
。 将以下修饰符添加到Button
:.disabled(!stack.canEdit(object: destination))
编辑按钮现在被禁用,除非您对此数据具有读/写权限。
最后,打开
HomeView.swift
并查找swipeActions
修饰符。 现在,您应该会看到> 一个带有Label("Delete", systemImage: "trash")
的Button
。 将以下修饰符添加到Button
:.disabled(!stack.canDelete(object: destination))
使用此代码,只有具有适当权限的用户才能执行编辑或删除等操作。
2. Challenge Two
目前您的应用程序存在一个小bug
。 如果您是共享数据的所有者,您可以随时停止共享此数据。 发生这种情况时,执行 cloudSharingControllerDidStopSharing(_:)
。 在此挑战中,更新代码,以便在不再与他人共享帖子时从第二个设备中删除此数据。
你想清楚了吗? 请参阅以下解决方案:
打开
CoreDataStack.swift
。 在isShared(object:)
下,添加:func isOwner(object: NSManagedObject) -> Bool { guard isShared(object: object) else { return false } guard let share = try? persistentContainer.fetchShares(matching: [object.objectID])[object.objectID] else { print("Get ckshare error") return false } if let currentUser = share.currentUserParticipant, currentUser == share.owner { return true } return false }
该方法:
- 检查对象是否有关联的
CKShare
。 如果不是,它立即返回false
。- 尝试通过
fetchShares(_:)
方法获取CKShare
。 如果没有找到任何匹配的共享,则返回 false。- 最后,如果该共享的当前用户是所有者,则返回 true。 否则,它返回 false。
使用此代码,打开
CloudSharingController.swift
并将以下代码添加到cloudSharingControllerDidStopSharing(_:)
:if !stack.isOwner(object: destination) { stack.delete(destination) }
就是这些! 现在,当您停止共享特定对象并且用户与
CloudKit
同步时,该对象将从他们的设备中删除。
在本教程中,您学习了使用 CloudKit
共享Core Data
的重要步骤,包括:
- 使用
NSPersistentCloudKitContainer
共享数据。 - 展示云共享视图。
- 接受共享邀请并获取共享数据。
- 区分
SwiftUI
中的私有数据和共享数据。
您了解了 iOS 15
中引入的新方法并解决了应用程序中的挑战和小bug
。
有关更多信息,请查看 Apple 关于 Build apps that share data through CloudKit and Core Data的视频。
这是 Apple 关于Synchronizing a Local Store to the Cloud的示例项目。
后记
本篇主要讲述了使用
SwiftUI App
中Core Data
和CloudKit
之间的数据共享,感兴趣的给个赞或者关注~~~