I have an app that starts a Live Activity on a certain user action. This Live Activity contains a button that the user can tap, which updates a SwiftData model instance. However, when you return to the main app after tapping the button on the Live Activity, the views do not update to reflect the changes, even though the changes were written to the database.
The underlying issue here is that the ModelContainer/ModelContext used by the AppIntent (performed from the LiveActivity when the button is tapped), are different from the instances in the main app. Meaning that while the changes are written to the underlying storage, the in-memory instances of ModelContext/ModelContainer in the main app don't get the changes from the extension, so SwiftUI doesn't update either.
What is the recommended way to handle this scenario? Or is there one? :) Shared access to a SwiftData container is clearly supported through App Groups, so is there not a mechanism to ensure changes made by an extension are updated in real-time for the main app?
Otherwise, it seems I would have to go through and manually rerun queries that views depend on to make sure they are showing the most recent data. This is cumbersome and error-prone.
Perhaps I'm missing something? Any suggestions would be greatly appreciated.
Post
Replies
Boosts
Views
Activity
I have a Live Activity with a button that updates a SwiftData model. This used to work in iOS 17, but not on iOS 18. The reason is that in iOS 17, when you run an AppIntent from a Live Activity, the perform() method would run in the main app's process, meaning it had access to the app's ModelContainer/ModelContext. However, in iOS 18, this is no longer the case, and the perform() method of an AppIntent now runs in the extension's process.
While I can still construct a new ModelContainer & ModelContext in the AppIntent's perform() method, the main app's container and context will not see these changes until the app is relaunched.
How can I make this work in iOS 18 now that an AppIntent executed from an extension runs in a different process from the main app?
I have a situation where tapping on a NavigationLink on an item from a SwiftData Query results in an infinite loop, causing the app the freeze. If you run the code, make sure to add at least 1 item, then tap on it to see the issue.
Here is the code for a small sample app I made to illustrate the issue:
import SwiftUI
import SwiftData
@main
struct TestApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Item.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
let container = try ModelContainer(for: schema, configurations: [modelConfiguration])
return container
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
struct ContentView: View {
var body: some View {
NavigationStack {
ListsView()
}
}
}
struct ListsView: View {
@Environment(\.modelContext) private var modelContext
@Query(filter: #Predicate<Item> { _ in true })
private var items: [Item]
var body: some View {
List(items) { item in
NavigationLink {
ItemDetail()
} label: {
VStack {
Text("\(item.name) | \(item.date.formatted())")
}
}
}
Button("Add") {
let newItem = Item(name: "Some item", date: .now)
modelContext.insert(newItem)
try? modelContext.save()
}
}
}
struct ItemDetail: View {
private var model = ItemModel()
var body: some View {
VStack {
Text("detail")
}
}
}
fileprivate var count = 0
class ItemModel {
var value: Int
init() {
value = 99
print("\(count)")
count += 1
}
}
@Model
final class Item {
let name: String
let date: Date
init(name: String, date: Date) {
self.name = name
self.date = date
}
}
In the test app above, the code in the initializer of ItemModel will run indefinitely. There are a few things that will fix this issue:
comment out the private var model = ItemModel() line in ItemDetail view
replace the @Query with a set list of Items
move the contents of the ListsView into the ContentView instead of referencing ListsView() inside the NavigationStack
But I'm not sure why this infinite loop is happening with the initializer of ItemModel. It seems like a SwiftData and/or SwiftUI bug, because I don't see a reason why this would happen. Any ideas? Has anyone run into something similar?
Is there any way to use metal-cpp in a Swift project? I have a platform layer I've written in Swift that handles Window/View creation, as well as event handling, etc. I've been trying to bridge this layer with my C++ layer as you normally would using a pure C interface, but using Metal instances that cross this boundary just doesn't seem to work.
e.g. Currently I initialize a CAMetalLayer for my NSView, setting that as the layer for the view. I've tried passing this Metal layer into my C++ code via a void* pointer through a C interface, and then casting it to a CA::MetalView to be used. When this didn't work, I tried creating the CA::MetalLayer in C++ and passing that back to the Swift layer as a void* pointer, then binding it to a CAMetalLayer type. And of course, this didn't work either.
So are the options for metal-cpp to use either Objective-C or just pure C++ (using AppKit.hpp)? Or am I missing something for how to integrate with Swift?