0

So I have this function, where I am comparing the password user entered(passed in variable 'password') with that available in the database( fetched in variable 'Pwd'). If the condition matches then I want the function to return value 1 else 0.

But I am facing issue with scope of variable. The count has the value 1 inside recordFetchedBlock only. and not outside.Can you suggest how I can make this function return 1 on password matching

func FetchRecords(user_name: String, password: String) -> Int {
        let pubData = CKContainer.default().publicCloudDatabase
        let predicate = NSPredicate(format: "Username = %@", user_name)
        let query = CKQuery(recordType: "Teachers", predicate: predicate)
        let operation = CKQueryOperation(query: query)
        var Pwd = String()
        var count = Int()
        operation.recordFetchedBlock = { (record : CKRecord!)  in
            let Pwd: String = record["Password"] as! String
            if Pwd == password{
                count=1
            }else{
                count=0
            }
        }
        operation.queryCompletionBlock = { cursor, error in
        }

        CKContainer.default().publicCloudDatabase.add(operation)
       return count
    }
Amrita Deb
  • 165
  • 1
  • 3
  • 15
  • You can't return something from a function which contains an asynchronous task. You need a completion handler, for example please look at [this question](https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function) – vadian Jan 14 '18 at 15:10
  • but say I define count as an array and append 1 to it if the 2 passwords match....can that also not be done? – Amrita Deb Jan 14 '18 at 17:12
  • In a completion handler you can pass anything. – vadian Jan 14 '18 at 17:14
  • I found this question...itis exactly my own question. Seems like it was a threading issue but I didnt quite get it. Can anyone help? https://stackoverflow.com/q/37506360/4502721 – Amrita Deb Jan 14 '18 at 17:32
  • It's not a threading issue, it's a timing issue. `recordFetchedBlock` returns its data much later after the `return count` line. CloudKit is heavily based on asynchronous operations. If you want to use it you have to understand the pattern of asynchronous data processing. Please read the documentation and watch the related WWDC videos. – vadian Jan 14 '18 at 17:39

1 Answers1

0

Thanks alot for the help @vadian. The code got fixed with Completion Handler.

Modified code looks like:

func FetchRecords(user_name: String, pass_word: String, completion:  @escaping (Bool)->()) -> Void {
        let pubData = CKContainer.default().publicCloudDatabase
        let predicate = NSPredicate(format: "Username = %@", user_name)
        let query = CKQuery(recordType: "Teachers", predicate: predicate)

        let operation = CKQueryOperation(query: query)
        operation.desiredKeys = ["Password"]

        operation.recordFetchedBlock = { (record)  in
            if pass_word == (record["Password"] as! String){
                print("Checkpoint1")
                let flag: Bool = true
                completion(flag)
            }else{
                print("Checkpoint2")
                let flag: Bool = false
                completion(flag)
            }
        }
        operation.queryCompletionBlock = { [unowned self] (cursor, error) in
            DispatchQueue.main.async {
                if error == nil {
                    print("Checkpoint3")
                }else{
                    let ac = UIAlertController(title: "Fetch failed", message: "There was a problem fetching records; please try again: \(error!.localizedDescription)", preferredStyle: .alert)
                    ac.addAction(UIAlertAction(title: "OK", style: .default))
                    self.present(ac, animated: true)
                }
            }
        }
        CKContainer.default().publicCloudDatabase.add(operation)

        print("Checkpoint4")
    }
Amrita Deb
  • 165
  • 1
  • 3
  • 15