我一直在沿着一个Hacking with Swift教程,他制作了一个应用程序,可以在iPhone,iPad和Mac版本的应用程序之间同步数据。所有的同步都由Core Data和Cloud Kit处理。
我一直在尝试将他所做的调整到我自己的应用程序中,该应用程序有一个配套的watchOS应用程序。
我将iOS应用和watchOS应用放在同一个应用组中,并使用正确的应用组标识符加载共享应用容器(我的小部件可以正常看到数据),但watch应用永远看不到数据。watch应用不会崩溃,它只是看不到任何要加载的内容,我得到的是一个空的实体数组。
手表应用程序可以不使用这种方法吗?我是否错过了一些关键步骤?
下面是DataController类:
import CoreData
import SwiftUI
class DataController: ObservableObject {
let container: NSPersistentCloudKitContainer
private var saveTask: Task<Void, Error>?
static var preview: DataController = {
let dataController = DataController(inMemory: true)
return dataController
}()
private var sharedStoreURL: URL {
let container = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.MyCo.MyApp1")!
return container.appendingPathComponent("Model.sqlite")
}
static let model: NSManagedObjectModel = {
guard let url = Bundle.main.url(forResource: "Model", withExtension: "momd") else {
fatalError("Failed to locate model file.")
}
guard let managedObjectModel = NSManagedObjectModel(contentsOf: url) else {
fatalError("Failed to load model file.")
}
return managedObjectModel
}()
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: "Model", managedObjectModel: Self.model)
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(filePath: "/dev/null")
} else {
container.persistentStoreDescriptions.first?.url = sharedStoreURL
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
container.persistentStoreDescriptions.first?.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator, queue: .main, using: remoteStoreChanged)
container.loadPersistentStores { _, error in
if let error {
fatalError("Fatal error loading store: \(error.localizedDescription)")
}
}
}
func remoteStoreChanged(_ notification: Notification) {
objectWillChange.send()
}
func save() {
saveTask?.cancel()
if container.viewContext.hasChanges {
try? container.viewContext.save()
}
}
func queueSave() {
saveTask?.cancel()
saveTask = Task { @MainActor in
try await Task.sleep(for: .seconds(3))
save()
}
}
func delete(_ object: NSManagedObject) {
objectWillChange.send()
container.viewContext.delete(object)
save()
}
private func delete(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
batchDeleteRequest.resultType = .resultTypeObjectIDs
if let delete = try? container.viewContext.execute(batchDeleteRequest) as? NSBatchDeleteResult {
let changes = [NSDeletedObjectsKey: delete.result as? [NSManagedObjectID] ?? []]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [container.viewContext])
}
}
func getMyEntities() throws -> [MyEntity] {
let request: NSFetchRequest<MyEntity> = MyEntity.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \MyEntity.name, ascending: true)]
let entities = try container.viewContext.fetch(request)
return entities
}
字符串
}
编辑--我缺少的关键部分是为iOS应用程序目标和watchOS应用程序目标添加两个功能。
首先,我需要在选择CloudKit服务的情况下添加iCloud功能,并创建一个要在iOS应用程序和watchOS应用程序之间共享的容器。
其次,我需要添加后台模式功能,并选择后台获取模式(仅适用于iOS)和远程通知模式(iOS和watchOS)。
1条答案
按热度按时间56lgkhnf1#
AppGroup容器用于同一设备中的应用程序。这就是为什么它在iOS应用程序和Widget之间工作。
AppGroups使用“进程间通信(IPC)”,这发生在设备上的共享内存中。AppGroups不支持iCloud或任何其他允许WatchOS连接的同步进程。
如果您想在iOS和WatchOS之间共享数据,可以使用CloudKit并在设备之间共享相同的iCloud容器,或者使用WatchConnectivity将新数据发送到WatchOS。
Hacking With Swift视频可能使用相同的CloudKit容器,这是最简单的选择。只需确保所有目标都匹配“签名和功能”
这里有一些有用的链接。
https://developer.apple.com/wwdc21/10003
https://developer.apple.com/documentation/coredata/mirroring_a_core_data_store_with_cloudkit/setting_up_core_data_with_cloudkit的
https://developer.apple.com/documentation/watchconnectivity/implementing_two-way_communication_using_watch_connectivity的