Querying private database in swift for user detail

2019-09-06 07:21发布

问题:

I'm trying to save and store the user's data, then retrieve it and check for a value, pushing the corresponding view controller.

However, despite only having 4 user records in my cloudkit dashboard, i'm getting 33 results, forcing me to change my code and preventing it from working.

This was my original code:

    let container = CKContainer.defaultContainer()
    let privateDB = container.privateCloudDatabase
    let resultPredicate = NSPredicate(format: "TRUEPREDICATE")
    let query = CKQuery(recordType: "UserData", predicate: resultPredicate)
    query.sortDescriptors = [NSSortDescriptor(key: "MODIFIED", ascending: false)]

    privateDB.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in

        if error != nil {
            print("\(error)")
        }
        else{

       for record in results! {

                self.weight = record["weight"] as? Int
                self.height = record["height"] as? Int
                self.age = record["age"] as? Int
                self.gender = record["genderFemale"] as? Int

                if self.weight == nil {
                    print("push weightVC")
                    let weightVC = WeightViewController()
                    self.navigationController?.pushViewController(weightVC, animated: false)
                }

                else if self.height == nil {
                    print("push heightVC")
                    let heightVC = HeightViewController()
                    self.navigationController?.pushViewController(heightVC, animated: false)
                }

                else if self.age == nil {
                    print("push ageVC")
                    let ageVC = DOBViewController()
                    self.navigationController?.pushViewController(ageVC, animated: false)
                }

                else if self.gender == nil{
                    print("push genderVC")
                    let genderVC = GenderViewController()
                    self.navigationController?.pushViewController(genderVC, animated: false)
                }
                else{
                    let planVC = PlanOriginViewController()
                    self.navigationController?.pushViewController(planVC, animated: false)
                }

I was forced to change it to this:

      privateDB.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in

        if error != nil {
            print("\(error)")
        }
        else{

            print("\(results?.count)")

            for record in results! {

                self.weight = record["weight"] as? Int
                self.height = record["height"] as? Int
                self.age = record["age"] as? Int
                self.gender = record["genderFemale"] as? Int

                self.arrayOfUserData?.addObject(record)
                print("record added")
            }

        }
    }

    print(arrayOfUserData)

    if arrayOfUserData != nil{
    let ckRecord = arrayOfUserData![0]

    self.weight = ckRecord["weight"] as? Int
    self.height = ckRecord["height"] as? Int
    self.age = ckRecord["age"] as? Int
    self.gender = ckRecord["genderFemale"] as? Int

    if self.weight == nil {
        print("push weightVC")
        let weightVC = WeightViewController()
        self.navigationController?.pushViewController(weightVC, animated: false)
    }

    else if self.height == nil {
        print("push heightVC")
        let heightVC = HeightViewController()
        self.navigationController?.pushViewController(heightVC, animated: false)
    }

    else if self.age == nil {
        print("push ageVC")
        let ageVC = DOBViewController()
        self.navigationController?.pushViewController(ageVC, animated: false)
    }

    else if self.gender == nil{
        print("push genderVC")
        let genderVC = GenderViewController()
        self.navigationController?.pushViewController(genderVC, animated: false)
    }
    else{
        let planVC = PlanOriginViewController()
        self.navigationController?.pushViewController(planVC, animated: false)
    }

    } else {

    }

However, this doesn't work as well. XCode is skipping over the privateDB query block and going straight to the line print(arrayOfUserData), before returning to the privateDB query.

Thanks!

回答1:

You issue is that you are assuming that your file is single threaded. What you want it to evaluate What fields are not filled in once you have received a results from the database query. What you need is a completion block. This lets you query the data base and then evaluate the results after. I would do something around these lines.

first add a completion handler that gives you a user object back. I assume you have a user defined should look something like this

struct User{
     weight:Int
     height:Int
     age:Int
     gender:Sting
 }

add your completion handler in your Query Method.

privateDB.performQuery(query, inZoneWithID: nil, completion:([User])) { (results, error) -> Void in

   let resutltData = results.value as [String:AnyObject] ?? [:]
       let users : [User] = resutltData.flatMap { record in
            let weight = record["weight"] as? Int ?? ""
            let height = record["height"] as? Int ?? ""
            let age = record["age"] as? Int ?? ""
            let gender = record["gender"] as? String ?? ""
       }
       completion(user)
}

now when you call privateDB.performQuery you should save it in a variable and preform your checks there. Something like this:

func ProcessUsers(){
    let users = privateDB.performQuery(query, inZoneWithID: nil, completion:{ (User) in 
    self.user = User
    switch user{
        case .weight:
            if .weight == "" {
                print("push weightVC")
                let weightVC = WeightViewController()
                self.navigationController?.pushViewController(weightVC, animated: false) } else {
                  fallthrough
               }

        case .height:
            if .height == "" {
                print("push heightVC")
                let heightVC = heightViewController()
                self.navigationController?.pushViewController(heightVC, animated: false) } else {
                  fallthrough
               }
        case .age:
            if .age == "" {
                print("push ageVC")
                let ageVC = ageViewController()
                self.navigationController?.pushViewController(ageVC, animated: false) } else {
                  fallthrough
               }
        case .gender:
            if .gender == "" {
                print("push genderVC")
                let genderVC = genderViewController()
                self.navigationController?.pushViewController(genderVC, animated: false) } else {
                  fallthrough
               }

Let me know if you have any more questions about this. I hope it helps.