I’m having an issue when two of my SwiftData models have a one-to-many relationship and I have them synced via CloudKit.
To be clear, I’ve met all of the requirements to make it iCloud friendly and sync to work. I followed this https://www.hackingwithswift.com/quick-start/swiftdata/how-to-sync-swiftdata-with-icloud, and can confirm I’ve done it correctly because initially I was seeing this crash on startup when I had not:
Thread 1: Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer)
This is to say, the problem may be iCloud related but it’s not due to a wrong model setup. Speaking of which, these are models:
@Model
class Film {
var name: String = ""
var releaseYear: Int = 0
var director: Director? = nil
init(name: String, releaseYear: Int, director: Director) {
self.name = name
self.releaseYear = releaseYear
self.director = director
}
}
@Model
class Director {
var name: String = ""
@Relationship(deleteRule: .cascade, inverse: \Film.director)
var films: [Film]? = []
init(name: String, films: [Film]) {
self.name = name
self.films = films
}
}
I’ve set the delete rule for the relationship between Film and Director to be cascading because you can’t have a film without a director (to be clear, even when set as nullify, it doesn’t make a difference)
And this is the @main App definition:
@main
struct mvpApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Film.self,
Director.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
}
And this is the dummy ContentView:
struct ContentView: View {
var body: some View {
EmptyView()
.onAppear {
let newDirector = Director(name: "Martin Scorcese", films: [])
let film = Film(name: "The Wolf of Wall Street", releaseYear: 2019, director: newDirector)
newDirector.films!.append(film)
}
}
}
I create a Director with no films assigned. I then create a Film, and the append it to the Director’s [Film] collection.
The last step however causes a crash consistently:
There is a workaround that involves removing this line from the Film init():
self.director = director // comment this out so it’s not set in a Film’s init()
When I do this, I can append the (Director-less) Film to the Director’s [Film] collection.
Am I misunderstanding how these relationships should work in SwiftData/CloudKit? It doesn’t make any sense to me that when two models are paired together that only one of them has a reference to the relationship, and the other has no knowledge of the link.
The above is a minimum reproducible example (and not my actual application). In my application, I basically compromised with the workaround that initially appears to be without consequence, but I have begun to notice crashes happening semi-regularly when deleting models that I suspect must be linked to setting the foundations incorrectly.
Post
Replies
Boosts
Views
Activity
My app is consistently crashing for a specific user on 14.3 (iMac (24-inch, M1, 2021) when their library is being retrieved in full. User says they have 36k+ songs in their library which includes purchased music.
This is the code making the call:
var request = MusicLibraryRequest<Album>()
request.limit = 10000
let response = try await request.response()
I’m aware of a similar (?) crash FB13094022 (https://forums.developer.apple.com/forums/thread/736717) that was claim fixed for 14.2. Not sure if this is a separate issue or linked.
I’ve submitted new FB13573268 for it.
CrashReporter Key: 0455323d871db6008623d9288ecee16c676248c6
Hardware Model: iMac21,1
Process: Music Flow
Identifier: com.third.musicflow
Version: 1.2
Role: Foreground
OS Version: Mac OS 14.3
NSInternalInconsistencyException: No identifiers for model class: MPModelSong from source: (null)
0 CoreFoundation +0xf2530 __exceptionPreprocess
1 libobjc.A.dylib +0x19eb0 objc_exception_throw
2 Foundation +0x10f398 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
3 MediaPlayer +0xd59f0 -[MPBaseEntityTranslator _objectForPropertySet:source:context:]
4 MediaPlayer +0xd574c -[MPBaseEntityTranslator _objectForRelationshipKey:propertySet:source:context:]
5 MediaPlayer +0xd5cd4 __63-[MPBaseEntityTranslator _objectForPropertySet:source:context:]_block_invoke_2
6 CoreFoundation +0x40428 __NSDICTIONARY_IS_CALLING_OUT_TO_A_BLOCK__
7 CoreFoundation +0x402f0 -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]
8 MediaPlayer +0xd5c1c __63-[MPBaseEntityTranslator _objectForPropertySet:source:context:]_block_invoke
9 MediaPlayer +0x11296c -[MPModelObject initWithIdentifiers:block:]
10 MediaPlayer +0xd593c -[MPBaseEntityTranslator _objectForPropertySet:source:context:]
11 MediaPlayer +0xd66c4 -[MPBaseEntityTranslator objectForPropertySet:source:context:]
12 MediaPlayer +0x1a7744 __47-[MPModeliTunesLibraryRequestOperation execute]_block_invoke
13 iTunesLibrary +0x16d84 0x1b4e1cd84 (0x1b4e1cd30 + 84)
14 CoreFoundation +0x5dec0 __invoking___
15 CoreFoundation +0x5dd38 -[NSInvocation invoke]
16 Foundation +0x1e874 __NSXPCCONNECTION_IS_CALLING_OUT_TO_REPLY_BLOCK__
17 Foundation +0x1cef4 -[NSXPCConnection _decodeAndInvokeReplyBlockWithEvent:sequence:replyInfo:]
18 Foundation +0x1c850 __88-[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:]_block_invoke_3
19 libxpc.dylib +0x10020 _xpc_connection_reply_callout
20 libxpc.dylib +0xff18 _xpc_connection_call_reply_async
21 libdispatch.dylib +0x398c _dispatch_client_callout3
22 libdispatch.dylib +0x21384 _dispatch_mach_msg_async_reply_invoke
23 libdispatch.dylib +0xad24 _dispatch_lane_serial_drain
24 libdispatch.dylib +0xba04 _dispatch_lane_invoke
25 libdispatch.dylib +0x16618 _dispatch_root_queue_drain_deferred_wlh
26 libdispatch.dylib +0x15e8c _dispatch_workloop_worker_thread
27 libsystem_pthread.dylib +0x3110 _pthread_wqthread
28 libsystem_pthread.dylib +0x1e2c start_wqthread
My current quota is for 2 million calls that is about to run out (3% left) with my subscription expiring on May 7. At this point, it’s become clear I will need around 2.5m calls a month.
Will my free 500k calls be used once my paid quota has finished? Based on my usage numbers per day, I believe so, but it’s unclear.
If I was to downgrade to 1m or re-subscribe to a 2m package, it says it will start after the current one expires, potentially resulting in downtime for a few days... unless my 500k calls will be used in the interim. I know if I was to upgrade to the 5m package, it will begin immediately, ensuring no downtime, but it will be unnecessary 1) if it was going to fallback to 500k free calls which is more than enough to cover usage for the few days before a new sub package begins and 2) because I don’t need 5m calls in a month.
Hope someone can help! I’ve contacted Apple but not heard anything so far. Thanks so much.