This is not an isolated issue for you and has been around since at least Xcode 12.
Somehow the Simulator's audio emulation clashes with the system audio giving you the pop and crackle.
While there is no official solution from Apple for this (yet) there is a workaround:
grab the Blackhole 2ch virtual audio device from https://existential.audio (it's free / open source)
after installing it launch your Simulator and wait for it to finish booting
from the Simulator's menu bar chose "I/O > Audio Output" and set it to "Blackhole 2ch"
[optional] repeat for "I/O > Audio Input"
This will make the Simulator send it's audio to the virtual device instead of the system speakers and will fix the pop/crackle.
Downside for now is that your Simulator won't play any audio since Blackhole will swallow it.
Post
Replies
Boosts
Views
Activity
I can still observe the original issue in the current iOS18.0 release version; The workaround also still works but it's been months and more than a few betas before the GM / public release yet this doesn't seem to have been addressed at all?
I started seeing the same issue after restructuring / refactoring some of my Swift projects - all of them relying on newly introduced @Macro syntax elements.
Good news: the error is unrelated to SwiftData and the crashes described further down in this thread are also unrelated to it (neither of my projects uses SwiftData so QED). I believe people are just seeing it more frequent on Xcode 16 + SwiftData because of the heavy use of Macros it introduced.
Using "Product" > "Clean Build Folder.." didn't solve the issue, however what did was the following:
"Product" > "Show Build Folder in Finder"
navigate up until you're in XCode's "DerivedData" folder
find and delete all folders starting with your Projects Name + some random identifier
restart Xcode
rebuild
So for example my project was called "GPS.io" and the folder was named something like "GPS.io-gsytifiksezewoesjjyadyzossvf" located in "/Users/USERNAME/Library/Developer/Xcode/DerivedData"
[EDIT] I'm on XCode 16.0 (16A242d) and testing against iOS 18.0
A few observations on the behaviour in iOS 18.0(.0 and .1) as well as the latest 18.1 beta:
changes from background contexts seem to sometimes be merged into the main context at irregular intervals
disabling autosave on the main context seems to also prevent propagation of any changes from background contexts
listening to .NSManagedObjectContextDidSave as suggested by DTS Engineer only helps in the most basic cases
The first two points make it feel like the MainActor context my SwiftUI views use only checks and merges changes whenever the internal autosave is triggered, even if there have been multiple notifications that the underlying NSManagedObjectContext has been saved by other sources.
As an experiment I tried to manually trigger modelContext.save() for the main context whenever I caught a notification for a background save however this doesn't seem to help with merging of background changes (it actually has no effect - the new data is in the store but it never makes it to any @Query update).
With no mentions of SwiftData in any of the Release Notes (18.0.x as well as 18.1 beta) it's anything but easy to keep faith in SwiftData in it's current, very fragile feeling implementation.
One point especially is giving me grey hairs right now - if an @Model contains an array of other @Model's and a property of one of those changes via a background context the changes do not propagate at all even if the workaround by DTS Engineer is applied.
import SwiftData
@Model
final class HistoryRecord {
// history records are added regularly via a background @ModelActor that also calls .save() on it's modelContext
var recordedAt: Date
var logbook: Logbook?
}
@Model
final class Logbook {
// every time a HistoryRecord is added lastUpdate is also set to the current date
var lastUpdate: Date
@Relationship(delete: .cascade)
var records: [HistoryRecord] = []()
var shelf: Bookshelf?
}
@Model
final class Bookshelf {
@Relationship(delete: .cascade)
var books: [Logbook]
}
struct BookshelfView: View {
@Environment(\.modelContext) private var modelContext
@Query shelves: [Bookshelf]
var body: some View {
ForEach(shelves) { shelf in
ForEach(shelf.books) { book in
// this number doesn't go up at all
Text("\(book.records.count) records in book")
}
}
}
}
Personally I'd go for an empty array instead of an optional array as it's a lot more readable to simply check for dates.isEmpty vs. if let dates = dates or guard let dates = dates else { .. } and then still having to check if there are actually any values inside the array.
From a SwiftData-Perspective neither version has advantages because you're storing an array of basic data types data types which SwiftData will have to serialise and store as a blob along with the Model instance they belong to.
Things would be different if we were talking about an array of @Model instances because then you'd be building a one-to-many relationship which is something that can be represented efficiently in any database and in which case you absolutely want to use var foos: [Foo] = []() in the class holding the array.
If you can see the data on Device 2 after closing and re-opening the app then you might be experiencing a known issue where SwiftData doesn't merge / update a model context used in SwiftUI if there is new background data (known since before 18.0 but apparently still an unaddressed issue in 18.1RC).