Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add record to Reference List for Record Type using CloudKit?

I have a two simple Record Types: Artwork and Artist. Artwork as a child may belong to one Artist, however one Artist may have multiply artworks.

Below are the screenshots related to mentioned Record Types.

enter image description here enter image description here

I can simply setup artist for artwork the following way:

let artistID = CKRecordID(recordName: "F297D690-888B-4B55-9FBD-27CAEF4BBD83")
let artworkID = CKRecordID(recordName: self.idTextField.text!)

self.container.publicCloudDatabase.fetchRecordWithID(artworkID, completionHandler: { artwork, error in

    if let artwork = artwork {

        artwork["artist"] = CKReference(recordID: artistID, action: CKReferenceAction.None)
        self.container.publicCloudDatabase.saveRecord(artwork, completionHandler: { artwork, error in

             print("done")
        })
    }
})

But the question is:

How to setup relationships in reversed relation? In other words how to add artworkID to the reference list of artistID?

Apple says:

...to represent the one-to-many relationship from Artist to Collection in the object model, add a reference field to the Collection record.

But how to do this?

like image 511
Bartłomiej Semańczyk Avatar asked Oct 23 '25 12:10

Bartłomiej Semańczyk


2 Answers

This is the simplest answer I have found:

let artworkID = CKRecordID(recordName: self.idTextField.text!)
if let artist = artist, var artworks = artist["artworks"] as? [CKReference] {

    let reference = CKReference(recordID: artworkID, action: CKReferenceAction.None)
    if !artworks.contains(reference) {
        artworks.append(reference)
    }
    artist["artworks"] = artworks

    //here you can save your changes or do whatever it needs
}
like image 199
Bartłomiej Semańczyk Avatar answered Oct 25 '25 03:10

Bartłomiej Semańczyk


The key to your problems can be found in the Apple documentation that says...

https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CKReference_class/

It is permissible to create circular owning references for a set of records.

To save multiple records containing references between them, save the target records first or save all the records in one operation using the same CKModifyRecordsOperation object.

The code to setup a reference in CloudKit I sure you seen?

    let uniqReference = NSUUID().UUIDString
    let unqUUID = CKRecordID(recordName: uniqUUID)
    let newRecord = CKRecord(recordType: "Blah", recordID: uniqUUID)

It says you need to save all your records @ the same time with a CKModifyOperation.

func saveLeCollection(theGlob:NSURL) {

    let container = CKContainer(identifier: "Blah.com")
    let publicDB = container.publicCloudDatabase

    let uniqUUID = CKRecordID(recordName: uniqReference)
    let newRecord = CKRecord(recordType: "Blah", recordID: uniqUUID)
    let whistleAsset = CKAsset(fileURL: theImage)
    newRecord["theImage"] = whistleAsset

    newRecord.setObject(uniqUUID, forKey: "theLink")

    var localChanges:[CKRecord] = []
    localChanges.append(newRecord)

    let saveRecordsOperation = CKModifyRecordsOperation(recordsToSave: localChanges, recordIDsToDelete: records2Erase)
    saveRecordsOperation.savePolicy = .ChangedKeys
    saveRecordsOperation.perRecordCompletionBlock =  { record, error in
        if error != nil {
            dispatch_async(dispatch_get_main_queue()) {
                self.showAlert(message: error!.localizedDescription)
                print(error!.localizedDescription)
            }
        }
        // deal with conflicts
        // set completionHandler of wrapper operation if it's the case
    }
    saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
        if error != nil {
            dispatch_async(dispatch_get_main_queue()) {
                self.showAlert(message: error!.localizedDescription)
                print(error!.localizedDescription)
            }
        } else {
            // deal with conflictsay
            // set completionHandler of wrapper operation if it's the case

            }
        }
    }

    saveRecordsOperation.qualityOfService = .Background
    publicDB.addOperation(saveRecordsOperation)
}

If I store the ArtistID in my artwork record, the same ID in every artwork record I have a many->one reference. And with my reference List I have one->many reference with my Artist record pointing to each artwork record.

like image 42
user3069232 Avatar answered Oct 25 '25 01:10

user3069232