问题
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.
来源:https://stackoverflow.com/questions/35691032/querying-private-database-in-swift-for-user-details