11

I'm confused about how to best save an object that contains an array of other objects in CloudKit.

Say I have a todo list app, which has different collections of items. How would I go about saving/fetching a whole collection of items?

Would I have a Record type of Collection, which would have a String Attribute called "Name", and then a Reference List Attribute called "Items"?

I know that the Record type of Item needs to have a Reference Attribute called "Collection", because of how CloudKit references from a child object to its parent.

I have managed to save a Collection without any instances of Item with the following code

func addCollection(collection: Collection!, completion: (error: NSError!) -> ()) {
    if collection == nil
        return
    }
    let collectionRecord = CKRecord(recordType: "Collection")
    CollectionRecord.setObject(collection.name, forKey: "Name")
    privateDB.saveRecord(collectionRecord) {
        record, error in
        dispatch_async(dispatch_get_main_queue()) {
           completion(error: error)
        }
    }
}

The other option is when saving a Collection, to loop through all instances of Item and also save those individually, their Reference Attribute to Collection making the connection on the CloudKit side, but this seems like way too many network calls.

William Robinson
  • 1,038
  • 17
  • 32

1 Answers1

3

For the Item records you need a CKReference to the Collection. You will then be able to set a CKReferenceAction on that. You don't need to create a CKReference list on the Collection.

Having a list of CKReference objects is only an option when you are planning to use CKReferenceAction.None Which would mean that there is not a strict relation between the two recordTypes

If you have a Collection object, then you can easily query the Item recordType using a predicate that Checks if the CKReference is that of the Collection.

Usually there is no need to save multiple records. Once you have created a Collection with Items the relation can remain unchanged. If you do need to change multiple records, then you could try using the CKModifyRecordsOperation which has support for saving multiple items in one action.

When linking existing Item recordTypes to a Collection, you do need to save each Item because it has a CKReference to the Collecion. The Item has changed, so it must be saved.

Edwin Vermeer
  • 13,017
  • 2
  • 34
  • 58
  • How do you guarantee the order of items in the collection then ? I'm afraid that when fetching the items, they would arrive in a different order than when they were saved ... – Frederic Adda Apr 07 '15 at 07:31
  • You can add a sort order like this: query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] – Edwin Vermeer Apr 07 '15 at 07:43
  • Yes but I need to keep the order of the array as set by the user, not apply a sort every time I fetch the array. – Frederic Adda Apr 07 '15 at 07:44
  • 3
    There are multiple solutions for maintaining a manual sort order. 1. create a separate record where you keep all the id's in the order you want. Then after changing the sort order you only have to change this one record. 2. create a linked list. each record will have a reference in it to the next record. When changing the sort order, you only have to change 3 records (new pointer, old pointer and current record). 3 put a sort order number in a record. You then have to update all records after a sort order change. – Edwin Vermeer Apr 07 '15 at 07:52
  • 1
    Ok thanks, I was afraid of that answer :-) I guess option 1 is my best bet. – Frederic Adda Apr 07 '15 at 07:53