BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

SOLVED: Show CloudKit Public Database info in List

Forums > SwiftUI

HI All,

i am brand new to this and am just starting to learn about swiftui in 2020 so have no knowledge of everything that came before.

I have created an app that uses cloudkit. I have a public database with some test data in.

All i am wanting is a very basic explanation of how to get that data from the cloudkit public database into a list in my app, it would also be amazing if you could show with file names, where you are putting bits of code.

I have a a record type called Shoes, in the record i have (brand, name, size)

I would like the user to have a list of all shoes that appeer in that database.

I would also appreciate filenames to go along with this if there is code in more than one file as i have been getting a little lost with the best practices of where to put code.

I know this is a big ask but i cannot find anything simple and strightforward out there in this new iteration of a language.

Thanks In Advance, Kind Regards

Adam

4      

I assume you have developer signing!

You will need to add iCloud to "Signing and Capabilities" and check CloudKit and the Container

You need where to store them a file called "Shoe"

import Foundation
import CloudKit

class Shoes: ObservableObject {
    @Published var lists: [Shoe] = []
}

struct Shoe: Identifiable {
    var id = UUID()
    var recordID: CKRecord.ID?
    var brand: String = ""
    var name: String = ""
    var size: Int = 0
}

then a file named "CKShoe"

import Foundation
import CloudKit

class CKShoe {
    static let database = CKContainer.default().publicCloudDatabase

    class func fetch(completion: @escaping (Result<[Shoe], Error>) -> ()) {
        let predicate = NSPredicate(value: true)
        let name = NSSortDescriptor(key: "name", ascending: true)
        let query = CKQuery(recordType: "Shoes", predicate: predicate)
        query.sortDescriptors = [name]

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

        var newShoes = [Shoe]()

        operation.recordFetchedBlock = { record in
            var shoe = Shoe()
            shoe.recordID = record.recordID
            shoe.brand = record["brand"] as! String
            shoe.name = record["name"] as! String
            shoe.size = record["size"] as! Int

            newShoes.append(shoe)
        }

        operation.queryCompletionBlock = { (cursor, error) in
            DispatchQueue.main.async {
                if let error = error {
                    completion(.failure(error))
                } else {
                    completion(.success(newShoe))
                }
            }
        }
        database.add(operation)
    }

then in View that has list

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var shoes: Shoes

    var body: some View {
      List {
         ForEach(shoes.lists, id: \.id) { shoe in
           Text(shoe.name) // What you want to show in List
         }
       }
       .onAppear(perform: loadShoes)
     }

  private func loadShoes() {
        CKShoe.fetch { (results) in
            switch results {
            case .success(let newShoes):
                self.shoes.lists = newShoes
            case .failure(let error):
                print(error) // handle error
            }
        }
    }
}

and also put in the SceneDelegate

let lists = Shoes()

let contentView = ContentView().environmentObject(lists)

Disclamer may have some error in as trying to type here(not in xcode) from my project using your record names etc. You might want to do the Project 33 which is in Swift the only difference is I used Result but you can do the CloudKit Fetch in the func loadShoes()

Good luck

7      

Thank you so much for taking the time to do this. Really is appreciated.

The code didnt have any errors as such but when i build the app, i get no data appearing in the view.

I have tried changing the list so that it displays static text Text("some text") per line but still nothing when running the app.

I will keep playing with stuff to try and get this to work. Will preview be able to show this data?

3      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

I found the issue, it was my end. My Database was not default().

Thank you so much for this info. This is the only place i have been able to get this info and that includes the posts i have put on apple developer forum.

3      

Hi Adam

No it will not show on Preview but in Simulator or real device.

Are you gettting data back. Put print("data") where completion(.success(newShoe)) to see if have data back. If not then there something wrong with the the fetch. which could be a number of things. eg signing capabilitys to entitlements.

I would do the Project 33 even in Swift so you get a better idea on how it works.

There are lots of things could go wrong so it not to List part.

Nigel

3      

Hi,

Am I understanding that a plublic database is not recorded on the user's device by default? You can use the .recordFetchedBlock instance property to record anything from the Public to the private database?

Tim

3      

HI @NigelGee,

Thanks a lot for sharing this! Super helpful! : )

I am trying to add a search binding to NSPredicate, as my goal is to search CloudKit Public DB (like apple music search for ex).

I created another post to not clutter things here... Reapply apprecate if you can give any suggetion! ; )

https://www.hackingwithswift.com/forums/swiftui/fetch-search-cloudkit-public-database/5077

3      

Hi @NigelGee,

Hey, I've got a question. Can you do this same thing with the private database? Basically all I want to know is are there records in the private database?

My app loads a local JSON file of Hymns and Im adding CloudKit support, but I dont want to load that local JSON if the cloud private database has records? I want to check this because If the user has an ipad and iphone and they load the app on their phone first then the local JSON file would load to CoreData and that will all load to the cloud. Then if they load the app on their ipad, I want to know if they have data in the local store for the Hymns entity and if they do, dont load the local JSON file.

How can I check to see if it has any records. I followed want you posted above but its not working. Do you have to have all the properties from the entity for this to work?

Any help would be greatly appreciated

Thanks Mark

3      

@appledad05

I do something similar to what you do, preloading some data via json. I opted to preload the data into it's own coredata entity that doesnt sync with CloudKit, at least initially.

The reason for this was the cloud sync can at times take longer than ideal and I needed to get the user into the app using it with the preloaded data without a possible delay. So basically, my preloaded data is not synced in CloudKit.

A better solution might actually be to utilise a public cloudkit db as readonly to hold all the preloaded data. I will probably end up doing this myself too, but I'm still very much learning for now. I would have to address any intial delays though still.

3      

Hey there,

I am working on a similar project written in Swift 5. I assume I could transport all of this into my project, except the part in the View which is in SwiftUI. Can someone tell me how to fetch the data in Swift 5?

3      

How would one do this now that SwiftUI has eliminated the SceneDelegate?

3      

Thanks for this topic.

I am trying it now but unfortunately I run into a problem on line 12:

static let database = CKContainer.default().publicCloudDatabase

With the error:

Terminating app due to uncaught exception 'CKException', reason: 'containerIdentifier can not be nil'
terminating with uncaught exception of type CKException'

I can't find anywhere what this is due to. Does anyone have a solution for this?

3      

This is my personal list that I update periodically for anyone who likes spreadsheets. I kept it on my notepad for about a year, but for a reason I had never imagined posting it. I will add another page shortly, consisting with tiny peep businesses I've built over the last 1.5 years.

Thank you to OP for the incredible catalogue and the hard effort! I'm sure I'll add some things to my list. It is fortunate for the community to have such you! Check my list as well - perhaps you can add some things to yours.

3      

Begin by looking at the ID number on the size tag. Should be something along the lines of "819847-101," with the 101 indicating the colour scheme. If it comes up with a different shoe (dirt bike riding boots) or a different colour scheme, you've got a fake.

3      

I’m here to show you all the details about the 10 best electric dirt bikes for kids that have been running hot in the market. Unlike any other place, I’ll also cover two things for you. I’ll let you know which one is the best among these 10 bikes, and also which bike can be the best budget pick for you.

3      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.