Search code examples
swiftrelationshipcloudkitswiftdata

How to solve relationship issues with SwiftData / CloudKit?


I have the following model set up in my app which utilizes SwiftData and Cloudkit. A Project object has an array of Book objects. A Book object has an array of Reader objects. A Reader object has an array of Comment objects. A Comment object has a reference to a Book object:

class Project
{
    @Relationship(deleteRule: .cascade, inverse: \Book.project) var books : [Book]?
    
    ...
}

class Book
{
    @Relationship(deleteRule: .nullify, inverse: \Reader.books) var readers : [Reader]?
    
    var project: Project?
    var comments: [Comment]?
    
    ...
}

class Reader
{
    @Relationship(deleteRule: .cascade, inverse: \Comment.reader) var comments: [Comment]?
    
    var book: [Book]?
    
    ...
}

class Comment
{
    @Relationship(deleteRule: .nullify, inverse: \Book.comments) var book: Book?

    var reader: Reader?
    
    ...
}

One other note is that Project and Reader are both root model objects (the same Reader can appear in different projects). That's why the Book classes's readers property deleteRule is set to .nullify instead of .cascade.

I have no issue with Project, Book, and Reader, I'm able to output Lists using the data from these classes and can see CloudKit updating them on multiple devices when I add / remove items. However, CloudKit stops working when the Comment class includes its two relationships properties from above (book? and reader?). When I remove those two properties, then CloudKit works fine again. (Note: I've also removed any other bit of code from the project that references the Comment class so I know that it's those two lines of code that are causing the problem.) When they're in there, I get a bunch of these type of errors in the log:

error: CoreData+CloudKit: -NSCloudKitMirroringDelegate _requestAbortedNotInitialized:: <NSCloudKitMirroringDelegate: 0x600003278a50> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringExportRequest: 0x600002e54a00> 7A3F34C3-4492-4B2C-B6D9-A0D00FCEE498' due to error: Error Domain=NSCocoaErrorDomain Code=134421 "Import failed because applying the accumulated changes hit an unhandled exception." UserInfo={NSLocalizedFailureReason=Import failed because applying the accumulated changes hit an unhandled exception., NSUnderlyingException=-[__NSDictionaryM UTF8String]: unrecognized selector sent to instance 0x600000d76560}

Is there a flaw in my model that's causing this? The relationship to Comment and Reader seems simple enough, it's the same type of relationship that I used between Project and Book, Book and Reader. The relationship with Comment and Book is a bit different, where I define one Book per Comment (and then need to include an array of Comments in the Book class to satisfy relationship requirement). The reason for this is because a Reader can have many different Comments across different Books and Projects, and need a way to filter them.

I'm lost as to what's going on here and feel it's due to a lack of a deeper understanding of CloudKit / SwiftData relationships, but am unable to find many resources on the issue. Any help would be appreciated.


Solution

  • When I renamed the Comment class to CommentX, everything worked as it should. So really this issue had nothing to do with code itself, but I guess there was something wrong with the CloudKit database, maybe due to an old faulty version of the Comment class. When I went into the CloudKit console and reset the environment on the side panel, I was able to name my class Comment again.