Hello, I have created a simple SwiftUI app with Core Data and want to be able to add data via the shortcuts app, I have implemented Intents and the IntentHandler class. When I create a shortcut to add data to my app and run it, nothing happens in the app, the list does not refresh, the only way to see the added data is to close the app completely and reopen it. How can I refresh the UI immediately? I will post my Core Data stack and my SwiftUI view.
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "SiriShort")
guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.SiriShortcut2")?.appendingPathComponent("SiriShort.sqlite") else {
fatalError("Shared file container could not be created.")
}
let storeDescription = NSPersistentStoreDescription(url: fileContainer)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [storeDescription]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
}
}
View:
import SwiftUI
import CoreData
import Intents
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@State private var view: Bool = false
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.text, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text(item.text!)
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.text = "\(Int.random(in: 0...1000))"
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
makeDonation(text: newItem.text!)
}
}
func makeDonation(text: String) {
let intent = MakeUppercaseIntent()
intent.text = text
intent.unit = "1"
intent.suggestedInvocationPhrase = "Add \(text) to app"
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
if error != nil {
if let error = error as NSError? {
print("Donation failed: %@" + error.localizedDescription)
}
} else {
print("Successfully donated interaction")
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
-
—
Jad-T
-
—
Sohrab ark
Add a CommentI tried to observe NSPersistentStoreRemoteChange like this:.onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { notification in DispatchQueue.main.async { let predicate = items.nsPredicate items.nsPredicate = nil items.nsPredicate = NSPredicate(value: true) items.nsPredicate = predicate } }
but the operation that I execute in the closure isn't efficient and gives me an issue: Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates
Did you tried to publish change in the main thread? (
DispatchQueue.main.async { // changes here..//}). Actually I have the same problem here. I need to update the list in the App after that new items has been added via Shortcut.