Fetching records in CloudKit fetch the entire record, including downloading any associated assets. This makes it not feasible to fetch many records at a time. Instead, we'll see how to fetch a subset of each record, keeping the overall size of the request small. We'll also introduce paging to request a single visible set of records at a time.
Episode Links Source Code CKQueryCursor Fetching Only Certain Keys CloudKit will fetch all keys, including large assets which makes this infeasible for our Photo record. Instead, we'll tell CloudKit to only download the thumbnail: let predicate = NSPredicate(format: "restaurant == %@", CKReference(recordID: restaurantID, action: .deleteSelf)) let query = CKQuery(recordType: Photo.recordType, predicate: predicate) let operation = CKQueryOperation(query: query) operation.desiredKeys = ["thumbnail"] We'll also tell the request to only fetch 12 records at a time. This number should be roughly the size of a single visible page of records. operation.resultsLimit = 12 Sorting the Results We want the newest photo to be first in the list, so we'll add a sort option to our query. To do this, we'll have to make sure that the attribute we're sorting by (creationDate in this case) is marked as sortable in the CloudKit Dashboard. query.sortDescriptors = [ NSSortDescriptor(key: "creationDate", ascending: false) ] Fetching Pages Sequentially In order to fetch the next page of records, we'll leverage CKQueryCursor. We'll start by making the function recursive, accepting an optional cursor parameter: private func loadPhotos(cursor: CKQueryCursor? = nil) { ... } We then need to initialize the operation with a cursor if we have one, otherwise we'll set up a new one with a query: if let c = cursor { operation = CKQueryOperation(cursor: c) } else { let predicate = NSPredicate(format: "restaurant == %@", CKReference(recordID: restaurantID, action: .deleteSelf)) let query = CKQuery(recordType: Photo.recordType, predicate: predicate) query.sortDescriptors = [ NSSortDescriptor(key: "creationDate", ascending: false) ] operation = CKQueryOperation(query: query) } When the operation is complete, we simply need to request the next page: operation.queryCompletionBlock = { cursor, error in if let e = error { print("Error fetching photos: \(e)") } else if let c = cursor { self.loadPhotos(cursor: c) print("Fetch more results...") } else { print("Done!") DispatchQueue.main.async { self.spinner.stopAnimating() } } }