简体   繁体   English

当我的核心数据存储已从后台扩展更新时,如何刷新我的 SwiftUI 视图?

[英]How do I refresh my SwiftUI view when my core data store has been updated from a background extension?

I have a SwiftUI app with an intents extension target.我有一个带有意图扩展目标的 SwiftUI 应用程序。 I also have a core data store located on a shared app group.我还有一个位于共享应用程序组的核心数据存储。

The intents extension can successfully write data to the store using newBackgroundContext() in the Shortcuts app. Intents 扩展可以使用 Shortcuts 应用程序中的newBackgroundContext()成功地将数据写入存储。 My SwiftUI app can read the data from the app group in viewContext but only when I force quit the app and re-open it.我的viewContext应用程序可以从 viewContext 中的应用程序组读取数据,但只有当我强制退出应用程序并重新打开它时。

I think I need a way to let my app know that it has been updated in a different context but I'm not sure how do do that?我想我需要一种方法让我的应用知道它已在不同的上下文中更新,但我不确定如何做到这一点?

I've tried setting context.automaticallyMergesChangesFromParent = true in the app delegate and adding context.refreshAllObjects() to onAppear in the SwiftUI view but that doesn't seem to make any difference.我尝试在应用程序委托中设置context.automaticallyMergesChangesFromParent = true并在 SwiftUI 视图中将context.refreshAllObjects()添加到onAppear ,但这似乎没有任何区别。

mergeChanges(fromContextDidSave:) seems promising but I'm not sure how to get the Notification. mergeChanges(fromContextDidSave:)看起来很有希望,但我不确定如何获得通知。

I'm new to Core Data and very confused, so any pointers in the right direction would be great, thanks!我是 Core Data 的新手并且非常困惑,所以任何正确方向的指针都会很棒,谢谢!

Here's a sanitised version of my current code:这是我当前代码的净化版本:

App Delegate应用代理

 lazy var persistentContainer: NSCustomPersistentContainer = {
        let container = NSCustomPersistentContainer(name: "exampleContainerName")
        container.loadPersistentStores { description, error in
            if let error = error {
                print("error loading persistent core data store")
            }
        }
        return container
    }()

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                print("error saving core data context")
            }
        }
    }

class NSCustomPersistentContainer: NSPersistentContainer {
    override open class func defaultDirectoryURL() -> URL {
        var storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "exampleAppGroupName")
        storeURL = storeURL?.appendingPathComponent("exampleContainerName")
        return storeURL!
    }
}

Scene Delegate场景代表

guard let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext else {
            fatalError("Unable to read managed object context.")
}

if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: ExampleView.environment(\.managedObjectContext, context))
            self.window = window
            window.makeKeyAndVisible()
}

Swift UI View Swift 用户界面视图

import SwiftUI
import CoreData

struct ExampleView: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(
        entity: ExampleEntityName.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \ExampleEntityName.date, ascending: false),
        ]
    ) var items: FetchedResults<ExampleEntityName>

    var body: some View {
        VStack {
            List(items, id: \.self) { item in
                Text("\(item.name)")
            }
        }
    }
}

Intent Extension意图扩展

class NSCustomPersistentContainer: NSPersistentContainer {
    override open class func defaultDirectoryURL() -> URL {
        var storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "exampleContainerName")
        storeURL = storeURL?.appendingPathComponent("exampleAppGroupName")
        return storeURL!
     }
}

let persistentContainer: NSCustomPersistentContainer = {
    let container = NSCustomPersistentContainer(name: "exampleContainerName")
    container.loadPersistentStores { description, error in
        if let error = error {
            print("error loading persistent core data store: \(error)")
        }
    }
    return container
}()

let context = persistentContainer.newBackgroundContext()

let entity = NSEntityDescription.entity(forEntityName: "ExampleEntityName", in: context)
let newEntry = NSManagedObject(entity: entity!, insertInto: context)
newEntry.setValue(Date(), forKey: "date")
newEntry.setValue("Hello World", forKey: "name")

do {
    try context.save()
} catch {
    print("Failed saving")
}

Don't know if you discovered an answer yet, but I had a similar problem using UserDefaults and an intent extension in a shared app group.不知道您是否找到了答案,但我在共享应用程序组中使用 UserDefaults 和意图扩展时遇到了类似的问题。 The thing that finally worked for me was adding a call to load the items in the method below in the SceneDelegate:最终对我有用的事情是在 SceneDelegate 的以下方法中添加调用以加载项目:

func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
        SiriResponseManager.shared.grabUD()
    }

In my example I am using a singleton that houses the method to load the items from the UserDefaults.在我的示例中,我使用的是 singleton,其中包含从 UserDefaults 加载项目的方法。 This singleton class is an ObservableObject.这个 singleton class 是一个 ObservableObject。 In my first view that loads (ContentView in my case) I assign an ObservedObject variable to my singleton class and retrieve the @State variables in my singleton to populate the string in my view.在我加载的第一个视图中(在我的情况下为 ContentView),我将 ObservedObject 变量分配给我的 singleton class 并检索我的 singleton 中的 @State 变量以填充我的视图中的字符串

Hopefully this helps.希望这会有所帮助。

class Data: ObservableObject {

    @Published var dataToUpdate: Int 
}

struct UpdateView : View {

@EnvironmentObject data: Data


   ...body ... {
     // use data.dataToUpdate here
  }
}

Just define data like you see in this example.只需像您在此示例中看到的那样定义数据。 Then fill dataToUpdate whenever your database changes...of course this is just a simplified example with just an Int Value...然后在您的数据库更改时填充 dataToUpdate ......当然这只是一个简单的例子,只有一个 Int 值......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 SwiftUI - 我如何知道何时单击了导航视图的后退按钮? - SwiftUI - How do I know when the back button of a navigation view has been clicked? 如何通知视图变量 state 已从 SwiftUI 中提取的子视图更新 - How to notify view that the variable state has been updated from a extracted subview in SwiftUI 如何在 SwiftUI 中为我的视图提供背景图像 - How can I give a background Image to my View in SwiftUI 如何刷新 SwiftUI 中的视图 - How do I refresh View in SwiftUI SwiftUI:当我从另一个初始化程序调用它时,如何让我的闭包返回“内容”而不是“一些视图”? - SwiftUI: How do I make my closure return 'Content' instead of 'some View' when calling it from another initialiser? 当用户使用 SwiftUI 进入新视图时如何刷新核心数据数组? - How to refresh Core Data array when user enters new view with SwiftUI? 在访问核心数据模型之前,如何确保已进行所有网络调用? - How do I ensure that all network calls have been made before accessing my core data model? 为什么当我的基础数据源更新时 SwiftUI 会自动向后导航,如何避免这种行为? - Why does SwiftUI automatically navigate backwards when my underlying data source is updated and how can I avoid this behavior? 如何将数据从 viewController 传递到 swiftUI 视图? - How do I pass data from viewController to swiftUI view? 如何从磁盘加载此图像数据并将其显示在我的 SwiftUI 列表中? - How do I load this image data from disk and present it in my SwiftUI List?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM