How to retrieve data from CloudKit using SwiftUI

I am using SwiftUI to make an app and storing the data on ICloud. Because all the code I can find relates to Swift and viewDidLoad and TableView, however this do not apply. I have written code and seems to retrieve it but will not return it to the ObservableObject to be able to display in the SwiftUI



The ObservableObject file:-

import SwiftUI
import Combine


final class ObservedData: ObservableObject {
    @Published var venues = venuesData
}


The query to retrieve data

import SwiftUI
import CloudKit


var venuesData: [Venue] = loadVenues()


func loadVenues() -> [Venue] {

    var data = [Venue]()

    let pred = NSPredicate(value: true)
    let sort = NSSortDescriptor(key: "id", ascending: true)
    let query = CKQuery(recordType: "DeptfordHopData", predicate: pred)
    query.sortDescriptors = [sort]

    let operation = CKQueryOperation(query: query)
    operation.desiredKeys = ["id","name", "address"]
    operation.resultsLimit = 50

    var newVenues = [Venue]()

    operation.recordFetchedBlock = { record in
        let venue = Venue()
        venue.racordID = record.recordID
        venue.id = record["id"]
        venue.name = record["name"]
        venue.address = record["address"]
        newVenues.append(venue)
    }

    operation.queryCompletionBlock = {(cursor, error) in
        DispatchQueue.main.async {
            if error == nil {
                data = newVenues
            } else {
                print(error!.localizedDescription)
            }
        }
    }

    CKContainer.default().publicCloudDatabase.add(operation)

    return data
}


I have got data showing when do breakpoint at line 40 in data but does not return to venueData

Replies

Curiously, this issue has nothing to do with SwiftUI. Rather, the problem is here:

var venuesData: [Venue] = loadVenues()

Here you initialise

venuesData
with the result from
loadVenues
. But
loadVenues
is an async routine (because it relies on CloudKit, and CloudKit always operates asynchronously).

Try setting a breakpoint on line 40 and line 44. You’ll find that line 44 runs first, because the line 40 is called asynchronously in response to a CloudKit operation completing. Moreover, at line 44 the

data
value will be empty, because you haven’t yet executed line 35.

To get this to work you’ll have to find a way to push the results of the async CloudKit operation into your

venues
property on
ObservedData
, and then set up your SwiftUI code to update based on that.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

To follow up on this with a bit more detail, when your CloudKit code finishes, and has all the venue data, it needs to modify the

venues
property of your
ObservedData
. Because that’s an
ObservableObject
and the property is
@Published
, SwiftUI can subscribe to that property. It will then receive the new value and update the UI accordingly.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"