Hi all,
I've been experiencing some issues using SwiftUI's List on macOS Monterey and macOS Ventura Beta 3, where my app will lock up with an error if I add and select items at the same time:
NSOutlineView error inserting child indexes <NSIndexSet: 0x600003401ea0>[number of indexes: 1 (in 1 ranges), indexes: (10)] in parent 0x0 (which has 9 children).
Minimal Reproducible Example
// Built with Xcode 14 Beta 3
struct MyData: Identifiable {
let id = UUID()
var text: String
}
struct ContentView: View {
@State var data: [MyData] = []
@State var selection = Set<UUID>()
var body: some View {
NavigationView {
List(data, selection: $selection) { item in
Text(item.text)
}
Button("Press Me!") {
DispatchQueue(label: "Worker").async {
for i in 0..<500 {
DispatchQueue.main.async {
data.append(MyData(text: String(i)))
}
usleep(100_000) // 0.1 seconds
}
}
}
}
}
}
As you can see, the app is just an empty Sidebar. When you press the button, a worker thread starts and it adds a new item to the Sidebar every 0.1 seconds (protected by DispatchQueue.main.async).
You can reproduce the example like this:
Run the app
Press the "Press Me!" button
As the items flow into the Sidebar, start randomly selecting some of those items in the Sidebar. Scrolling at the same time also helps in reproducing this issue.
Eventually, the app should lock up and an error message should appear in the console.
You can see a video of how to reproduce here: https://imgur.com/a/GqjILi2
What I've tried
I've tried replacing the DispatchQueue with Task and Task.detached, and using try await Task.sleep instead of usleep, but this doesn't seem to help at all.
I've tried moving the work and data into a separate ViewModel class. The same issue occurs.
I've tried completely replacing the "Worker" queue, and instead just using DispatchQueue.main.asyncAfter, and the issue still occurs.
I've tried using Timer.scheduledTimer instead of running in a background queue, and this actually works. However, in my real code base, I'm actually processing an AsyncStream that continuously emits data. The usleep in the MRE is just to simulate work.
I'm really puzzled as to what's going on. It looks like this code is thread safe, but Timer.scheduledTimer works and it callbacks on the main queue.
Could this potentially be a bug with SwiftUI macOS? If so are there any ways to alleviate this issue?
Update: This post mentions a warning
Update NavigationAuthority bound path tried to update multiple times per frame
Which is similar to some of the log messages I'm also getting. They also mention how the app often freezes when navigated with a NavigationLink, similar to this issue.
Note: This post is mostly a duplicate of my StackOverflow post here.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hi,
I was testing the new iOS 18 behavior where NSPersistentCloudKitContainer wipes the local Core Data store if the user logs out of iCloud, for privacy purposes.
I ran the tests both with a Core Data + CloudKit app, and a simple one using SwiftData with CloudKit enabled. Results were identical in either case.
In my testing, most of the time, the feature worked as expected. When I disabled iCloud for my app, the data was wiped (consistent with say the Notes app, except if you disable iCloud it warns you that it'll remove those notes). When I re-enabled iCloud, the data appeared. (all done through the Settings app)
However, in scenarios when NSPersistentCloudKitContainer cannot immediately sync -- say due to rate throttling -- and one disables iCloud in Settings, this wipes the local data store and ultimately results in data loss.
This occurs even if the changes to the managed objects are saved (to the local store) -- it's simply they aren't synced in time.
It can be a little hard to reproduce the issue, especially since when you exit to the home screen from the app, it generally triggers a sync. To avoid this, I swiped up to the screen where you can choose which apps to close, and immediately closed mine. Then, you can disable iCloud, and run the app again (with a debugger is helpful). I once saw a message with something along the lines of export failed (for my record that wasn't synced), and unfortunately it was deleted (and never synced).
Perhaps before NSPersistentCloudKitContainer wipes the local store it ought to force sync with the cloud first?
I have a single multiplatform application that I use NSPersistentCloudKitContainer on.
This works great, except I noticed when I open two instances of the same process (not windows) on the same computer, which share the same store, data duplication and "Metadata Inconsistency" errors start appearing.
This answer (https://stackoverflow.com/a/67243833) says this is not supported with NSPersistentCloudKitContainer.
Is this indeed true?
If it isn't allowed, is the only solution to disable multiple instances of the process via a lock file? I was thinking one could somehow coordinate a single "leader" process that syncs to the cloud, with the others using NSPersistentContainer, but this would be complicated when the "leader" process terminates.
Currently, it seems iPad split views are new windows, not processes -- but overall I'm still curious :0
Thank you!