Array out of index when getting PFFile from Parse - swift

My app gets the images just fine but if I scroll up and down for a while and then pull to refresh, it crashes and says array out of index. This does not happen every time. I believe it has something to do with the fact that I am not using getdatainbackground but when I go to use that instead of getData(), it loops faster than it can actually retrieve the files and they are out of order.
My current code also gives me this error: Break on warnBlockingOperationOnMainThread() to debug.
2016-03-02 00:35:48.630 App Name[1137:96655] Warning: A long-running operation is being executed on the main thread.
if Reachability.isConnectedToNetwork() {
self.skip = 0
//--RESETTING THE ARRAYS FOR DATA--\\
self.contactText.removeAll(keepCapacity: true)
self.names.removeAll(keepCapacity: true)
self.images.removeAll(keepCapacity: true)
self.prices.removeAll(keepCapacity: true)
self.sizes.removeAll(keepCapacity: true)
self.conditions.removeAll(keepCapacity: true)
self.dates.removeAll(keepCapacity: true)
self.ids.removeAll(keepCapacity: true)
self.createdBy.removeAll(keepCapacity: true)
//--RESET THE USERS LOCATION WHEN HE REFRESHES IN CASE OF A DARASTIC MOVE IN LOCATION--\\
let userGeoPoint = PFUser.currentUser()!["location"] as! PFGeoPoint
//--GETTING ALL OF THE OBJECTS WITHIN 60 MILES OF USERS CURRENT LOCATION--\\
let query = PFQuery(className:"Shoes")
query.whereKey("Location", nearGeoPoint: userGeoPoint, withinMiles: 60)
let user = PFUser.currentUser() as PFUser!
let array: AnyObject? = user["blockedUsers"]
if(array != nil){
query.whereKey("createdBy", notContainedIn: array! as! [AnyObject])
}
query.limit = 50
query.orderByDescending("createdAt")
query.skip = self.skip
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
print("Successfully retrieved \(objects!.count) scores.")
for object in objects! {
if let dateCreated = object.createdAt as NSDate? {
self.dates.append(dateCreated)
}
self.contactText.append(object["Contact"] as! String)
self.descriptions.append(object["Description"] as! String)
self.names.append(object["Name"] as! String)
if object["price"] as! String == "" || object["price"] == nil{
self.prices.append("Negotiable")
}else{
self.prices.append(object["price"] as! String)
}
if object["size"] as! String == "" || object["size"] == nil{
self.sizes.append("N/A")
}else{
self.sizes.append(object["size"] as! String)
}
if object["conditionType"] as! String == "" || object["conditionType"] == nil{
self.conditions.append("N/A")
}else{
self.conditions.append(object["conditionType"] as! String)
}
self.ids.append(object.valueForKey("objectId") as! String)
self.createdBy.append(object["createdBy"] as! String)
let imageFile = object["imageFile"] as! PFFile
let imageData = imageFile.getData()
if (imageData != nil) {
let image = UIImage(data:imageData!)
self.images.append(image!)
}
}
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
else {
print(error)
}
self.refresher.endRefreshing()
}
self.skip+=50
} else {
print("Internet connection not available")
self.refresher.endRefreshing()
let alert = UIAlertView(title: "No Internet connection", message: "Please ensure you are connected to the Internet", delegate: nil, cancelButtonTitle: "OK")
alert.show()
}

Try adding a check to make sure your arrays aren't empty when assigning data to cells.

Related

shared database zones cannot be found

I have sucessfully shared a record from private database customzone.
share url Optional(https://www.icloud.com/share/0N9smwzXZ0gfumZv8jyVo7uag)
When I print shared record I get this:
record completion <CKShare: 0x106702100; participants=(
"<CKShareParticipant: 0x2817115e0; hasProtectionInfo=1, isCurrentUser=YES, participantID=E742CBD3-41C9-4A9E-A392-08914E8C1D37, permission=readWrite, role=owner, acceptanceStatus=Accepted, identity=<CKUserIdentity: 0x281815ce0; lookupInfo=<CKUserIdentityLookupInfo: 0x2832ba910; email=vhrao#icloud.com>, cached=0, nameComponents=viswanatha, userID=<CKRecordID: 0x283c6f940; recordName=__defaultOwner__, zoneID=_defaultZone:__defaultOwner__>, contactIdentifiers={\n items = (\n );\n}>>"
), allowsReadOnlyParticipantsToSeeEachOther=YES, publicPermission=none, recordChangeTag=2z, rootRecordID=<CKRecordID: 0x283c39360; recordName=645B675E-121F-4DC8-B86D-8968C8DE7B1C-9651-00000ED7A0D0E95D, zoneID=userProfileZone:__defaultOwner__>, routingKey=0N9, recordID=Share-967C18F4-43C4-4958-9D40-6D890DD205AD:(userProfileZone:__defaultOwner__), recordType=cloudkit.share, etag=2z> and nil
record completion <CKRecord: 0x10bc05ac0; recordID=645B675E-121F-4DC8-B86D-8968C8DE7B1C-9651-00000ED7A0D0E95D:(userProfileZone:__defaultOwner__), recordChangeTag=30, values={
asOfDate = "2020-08-01 20:26:44 +0000";
latitude = "29.9288104125185";
locationId = "1D2A93A8-A22C-4B2A-9EC6-86F646667F3E-8282-00000CF78F38B1DB";
locationType = "Household User";
longitude = "-95.6080147578347";
profileImage = "<CKAsset: 0x10bc05f60; referenceSignature=<01ebb50c 4bd0e618 bb0f4486 b486145b 30f22689 83>, uploadRank=0, path=/private~/Library/Caches/CloudKit/0fce42f4be876f65546aa1b4549b3658e9291963/Assets/B21AB25E-C07A-4D65-9238-61A17B3E6372.01b1f7f738f239ee006815df2bb2896fade0f08229, size=34656, UUID=B21AB25E-C07A-4D65-9238-61A17B3E6372, signature=<01b1f7f7 38f239ee 006815df 2bb2896f ade0f082 29>, wrappedAssetKey=<24 bytes>>";
userType = "Consumer";
}, share=<CKReference: 0x283c38ae0; recordID=<CKRecordID: 0x283c390c0; recordName=Share-967C18F4-43C4-4958-9D40-6D890DD205AD, zoneID=userProfileZone:__defaultOwner__>>, recordType=infrastructure> and nil
Then I fetch RecordZones
func fetchRecordZones(completion: #escaping (CKRecordZoneID?, Error?) -> Void) {
var fetchedRecordZones: [CKRecordZoneID : CKRecordZone]? = nil
let fetchZonesOperation = CKFetchRecordZonesOperation.fetchAllRecordZonesOperation()
fetchZonesOperation.fetchRecordZonesCompletionBlock = { (recordZones: [CKRecordZoneID : CKRecordZone]?, error: Error?) -> Void in
guard error == nil else {
completion(nil, error)
return
}
if let recordZones = recordZones {
fetchedRecordZones = recordZones
for recordID in recordZones.keys {
print(recordID.zoneName)
if (recordID.zoneName == Cloud.SharedZone.UserProfile.ZoneName) {
completion(recordID, nil)
}
}
}
completion(nil, nil)
}
fetchZonesOperation.qualityOfService = .utility
self.sharedDB?.add(fetchZonesOperation)
}
I get no recordZones
I go to coud Kit and look at the shared database and fetch zones with fetch with change Token checkbox enabled I get name: userProfileZone owner record name:_9d4825db9b0aa911655e420ec0016129
Looks like it has a zone in shared database. At least seems like, so why am I not getting zones from shared database?
//Sharing code
var lookupInfos = [CKUserIdentity.LookupInfo]()
let creatorID = rootRecord.creatorUserRecordID
self.defaultContainer?.discoverUserIdentity(withUserRecordID: creatorID!) { [weak self] (userIdentity, error) in
guard error == nil else {
if let ckerror = error as? CKError {
self!.aErrorHandler.handleCkError(ckerror: ckerror)
}
completion(false, error)
return
}
if let userIdentity = userIdentity {
lookupInfos.append(userIdentity.lookupInfo!)
let share = CKShare(rootRecord: rootRecord)
share[CKShareTitleKey] = "Infrastructure" as CKRecordValue
//share[CKShareThumbnailImageDataKey] = shoppingListThumbnail as CKRecordValue
share[CKShareTypeKey] = "com.nr2r.infrastructure" as CKRecordValue
if let lookupInfo = userIdentity.lookupInfo {
let op: CKFetchShareParticipantsOperation = CKFetchShareParticipantsOperation(userIdentityLookupInfos: [lookupInfo])
op.fetchShareParticipantsCompletionBlock = { error in
if let error = error {
print("error: ", error)
}
}
op.shareParticipantFetchedBlock = { participant in
participant.permission = .readWrite
share.addParticipant(participant)
let modOp: CKModifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [rootRecord, share], recordIDsToDelete: nil)
modOp.savePolicy = .ifServerRecordUnchanged
modOp.perRecordCompletionBlock = {record, error in
print("record completion \(record) and \(String(describing: error))")
}
modOp.modifyRecordsCompletionBlock = {records, recordIDs, error in
guard let ckrecords: [CKRecord] = records, let record: CKRecord = ckrecords.first, error == nil else {
print("error in modifying the records " + error!.localizedDescription)
completion(false, error)
return
}
if let records = records {
for record in records {
print ("recordType: \(record.recordType)")
if (record.recordType == "cloudkit.share") {
self!.sharedCKRecordZoneID = record.recordID.zoneID
}
print ("recordName: \(record.recordID.recordName)")
print ("zoneID: \(record.recordID.zoneID.zoneName)")
print ("zoneID: \(record.recordID.zoneID.ownerName)")
}
}
if let anURL = share.url {
print("share url \(String(describing: share.url))")
completion(true, nil)
}
}
self?.privateDB?.add(modOp)
}
self?.defaultContainer?.add(op)
}
} else {
completion(false, nil)
}
}
More edits to show how to retrieve shared record:
let op = CKFetchShareMetadataOperation(shareURLs: [aURL])
op.perShareMetadataBlock = { shareURL, shareMetadata, error in
if let shareMetadata = shareMetadata {
if shareMetadata.participantStatus == .accepted {
let query = CKQuery(recordType: Cloud.Entity.Infrastructure, predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
let zone = CKRecordZoneID(zoneName: Cloud.PrivateZone.UserProfile.ZoneName, ownerName: (shareMetadata.ownerIdentity.userRecordID?.recordName)!)
self.sharedDB?.perform(query, inZoneWith: zone, completionHandler: { (records, error) in
if let ckerror = error as? CKError {
self.aErrorHandler.handleCkError(ckerror: ckerror)
completion(nil, error)
} else if let records = records, let firstRecord = records.first {
completion(firstRecord, nil)
}
})
}
}
Fetching shared database zones return zero
self.sharedDB?.fetchAllRecordZones(completionHandler: { (ckrecordZones, error) in
guard error == nil else {
if let ckError = error as? CKError {
self.aErrorHandler.handleCkError(ckerror: ckError)
}
completion (nil, error)
return
}
if let recordZones = ckrecordZones {
for i in 0 ..< recordZones.count{
// find the zone you want to query
if recordZones[i].zoneID.zoneName == Cloud.SharedZone.UserProfile.ZoneName {
completion (recordZones[i].zoneID, nil)
}
}
}
completion (nil, nil)
})

Function does not return array. Download photos from Firebase Storage matching Firebase Database file names [duplicate]

This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 4 years ago.
I have images stored in FireBase Storage, and matching file name data in FireBase Database, and I want to get those photos and display them (note, there is still some code I need to write because I am not getting EVERY photo from storage. Just those that are returned from a query of the database)
Here is the git repo
This code in DBHandler works, as I can see the print of the image file names
func photoListForLocation() -> [String]{
let file_name:String = String()
var photos = [file_name]
ref.observeSingleEvent(of: .value) { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]{
for snap in snapshot {
if let data = snap.value as? [String:Any]{
let imageName:String = data["image_name"]! as! String
photos.append(imageName)
print("photos.append - \(imageName)")
}//if let data
}//for
}//snapshot
}//ref.observeSingleEvent
return photos
}//photoListForLocation
BUT the "return photos" never happens.. So the following in my ViewController does nothing..
let dbHandler:DBHandler = DBHandler()
var fileList = [String]()
fileList = dbHandler.photoListForLocation()
fileList.forEach {fileName in
print("\(fileName)")
}
Of course, if there is a better or simpler way of accomplishing my goal, I'm all ears.
for Mr. Tomato... (see comments)
import Foundation
import FirebaseDatabase
import GoogleMaps
class DBHandler {
var ref:DatabaseReference! = Database.database().reference().child("locations")
var imageCount:Int = 0
func addLocation(coordinate:CLLocationCoordinate2D, rating: Double, imageName: String?){
let location = ["latitude": coordinate.latitude,
"longitude": coordinate.longitude,
"rating": rating,
"image_name": imageName!,
"postDate": ServerValue.timestamp()
] as [String : Any]
self.ref.childByAutoId().setValue(location)
}//end setLocation
func getImageListForLocation(lattitude:Double, longitude:Double) -> [String]{
var images = [String]()
self.ref.observeSingleEvent(of: .value) { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]{
for snap in snapshot {
if let data = snap.value as? [String:Any]{
let thisLattitude = data["latitude"]
let thisLongitude = data["longitude"]
guard let imageName = data["image_name"] else {return}
if lattitude == thisLattitude as! Double && longitude == thisLongitude as! Double {
images.append(imageName as! String)
}//if
}//if
}//for
}//if
}//ref
self.imageCount = images.count
return images //DOES NOT RETURN IMAGES!! (FILE NAMES)
}//getImageListForLocation
}//DBHandler
In order to get the photos and display them, you need to store the Storage URL of the photo location in your database for later use. Here are a couple of functions I created for a project that does this.
This application has a list of Angels that it saves and retrieves. Angels have names, numbers, emails, and images. I store a local array of these angels in a datasource I've defined in PageDataSource.sharedInstance(). The boolean crudIsAvailable is to make sure there is a connection. On verifying that CRUD operations are available I being scrubbing the list of angelsToSave:
func saveAngels(_ completion: #escaping(_ error: Error?) -> Void) {
if PageDataSource.sharedInstance.crudIsAvailable == true {
let angelsRef = ref.child("angels")
let myAngelsRef = angelsRef.child(id)
for item in PageDataSource.sharedInstance.angelsToSave {
let angel = PageDataSource.sharedInstance.angels[item]
let angelNameRef = myAngelsRef.child(angel.name!)
var angelToSave = getAngel(angel)
var jpegRepresentation : UIImage? = nil
if let photo = angel.photo {
jpegRepresentation = photo
} else {
jpegRepresentation = UIImage(named: "Anonymous-Seal")
}
if let photoData = UIImageJPEGRepresentation(jpegRepresentation!, 1.0) {
storePhoto(photoData, angel.name!, completion: { (url, err) in
if err != nil {
print(err?.localizedDescription)
angelToSave["photo"] = nil
myAngelsRef.updateChildValues(angelToSave, withCompletionBlock: { (error, ref) in
if error != nil {
completion(error!)
} else {
completion(nil)
}
})
} else {
angelToSave["photo"] = url?.absoluteString
angelNameRef.updateChildValues(angelToSave)
completion(nil)
}
})
}
}
} else {
completion(NSError(domain: "Unavailable", code: 0, userInfo: nil))
}
}
The important part of saveAngels() is if let photoData..... storePhoto() and here is the storePhoto() function.
func storePhoto(_ photo: Data, _ name: String, completion: #escaping (_ result: URL?, _ error: NSError?) -> Void) {
let storageRef = Storage.storage().reference().child(name)
storageRef.putData(photo, metadata: nil) { (storageMetaData, err) in
if err != nil {
completion(nil, NSError(domain: (err?.localizedDescription)!, code: 0, userInfo: nil))
} else {
completion(storageMetaData?.downloadURL(), nil)
}
}
}
The function storePhoto() returns the value of the URL through a completion handler and the saveAngels() function takes that information and uses it to store the data to the realtime database for future use.
For a better understanding here is my Angel object:
class Angel: NSObject {
var name: String?
var email: [String]?
var phone: [String]?
var photo: UIImage?
var filepath: String?
}
And here is how I download the photo:
First, I retrieve the list of photo URLs to an array of "angels" in a datasource singleton on VC load then I load the images as they appear in a collectionView like this.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as! AngelCollectionViewCell
cell.imageView?.contentMode = .scaleAspectFill
cell.activityIndicator.hidesWhenStopped = true
cell.activityIndicator.startAnimating()
if let pic = PageDataSource.sharedInstance.angels[indexPath.row].photo {
cell.imageView?.image = pic
cell.activityIndicator.stopAnimating()
cell.setNeedsLayout()
} else if let imgURL = PageDataSource.sharedInstance.angels[indexPath.row].filepath {
Storage.storage().reference(forURL: imgURL).getData(maxSize: INT64_MAX, completion: { (data, error) in
guard error == nil else {
print("error downloading: \(error!)")
return
}
// render
let img = UIImage.init(data: data!)
// store to datasource
PageDataSource.sharedInstance.angels[indexPath.row].photo = img
// display img
if cell == collectionView.cellForItem(at: indexPath) {
DispatchQueue.main.async {
cell.imageView?.image = img
cell.activityIndicator.stopAnimating()
cell.setNeedsLayout()
}
}
})
} else {
// TODO: TODO: Change Image to a proper placeholder
cell.imageView.image = UIImage(contentsOfFile: "Angels#2x.png")
cell.Label.text = PageDataSource.sharedInstance.angels[indexPath.row].name!
cell.activityIndicator.stopAnimating()
}
return cell
}
The important code really starts with Storage.storage I hope this helps!!

Swift CloudKit not working with Cellular (Time exceeded)

I'm using following code to fetch Data from iCloud:
func fetchShoppingList() {
let container = CKContainer.default()
let publicDB = container.publicCloudDatabase
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "ShoppingList", predicate: predicate)
let operation = CKQueryOperation(query: query)
operation.allowsCellularAccess = true
operation.qualityOfService = .userInitiated
publicDB.add(operation)
publicDB.perform(query, inZoneWith: nil) { [unowned self] results, error in
if error != nil {
print(error)
}
else {
for var value in results! {
let shoppingListEntry = ShoppingListEntry()
shoppingListEntry.index = value.value(forKey: "index") as! Int
shoppingListEntry.product = value.value(forKey: "product") as! String
shoppingListEntry.amount = value.value(forKey: "amount") as! Int
shoppingListEntry.priority = value.value(forKey: "priority") as! Int
if value.value(forKey: "isSelected") as! String == "true" {
shoppingListEntry.isSelected = true
}
else {
shoppingListEntry.isSelected = false
}
self.shoppingListEntrys.append(shoppingListEntry)
}
OperationQueue.main.addOperation({ () -> Void in
self.tableViewShoppingList.reloadData()
})
}
}
}
Everything works fine if my phone is connected via Wifi, but if I'm using Cellular I get following error: CKError 0x170244e30: "Network Failure" (4/-1001); "Zeitüberschreitung bei der Anforderung." So there seems to be a problem with time exceeding. I looked for a solution and found a post, saying I have to add the operation lines but nothing changed.
Can anybody help me please?

How do I retrieve data by using the Parse PFQuery?

Hi I'm trying to retrive data by using the PFQuery.
loadPosts in the tabelviewController.
My problem is commentsArray.
As you can see... commentsArray is not synchronized other arryas.
Because It has different db's class.
I want get all the data arrays to set the uilabel's text synchronizing
How do I achieve that?
I also had trying to parse's synchronized method. but It is really slow.
Here is my code. This function in the TableViewController.
func loadPosts() {
//STEP 1. Find posts related to people who we are following
let followQuery = PFQuery(className: "fans")
followQuery.whereKey("myfans", equalTo: PFUser.currentUser()!.username!)
followQuery.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.followArray.removeAll(keepCapacity: false)
//Appending where people following..
//find related objects
for object in objects! {
self.followArray.append(object.objectForKey("fan") as! String)
}
//append current user to see own posts in feed
self.followArray.append(PFUser.currentUser()!.username!)
//STEP 2. Find posts made by people appended to followArray
let query = PFQuery(className: "posts")
query.whereKey("username", containedIn: self.followArray)
query.limit = self.page
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
self.usernameArray.removeAll(keepCapacity: false)
self.profileArray.removeAll(keepCapacity: false)
self.dateArray.removeAll(keepCapacity: false)
self.postArray.removeAll(keepCapacity: false)
self.descriptionArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
//For Test
self.commentsArray.removeAll(keepCapacity: false)
self.isTappedLikeArray.removeAll(keepCapacity: false)
//find related objects
for object in objects! {
self.usernameArray.append(object.objectForKey("username") as! String)
self.profileArray.append(object.objectForKey("profileImg") as! PFFile)
self.dateArray.append(object.createdAt)
self.postArray.append(object.objectForKey("postImg") as! PFFile)
self.descriptionArray.append(object.objectForKey("title") as! String)
self.uuidArray.append(object.objectForKey("uuid") as! String)
//STEP 3.
//Check Comment
let countQuery = PFQuery(className: "comments")
countQuery.whereKey("to", equalTo: object.objectForKey("uuid") as! String)
countQuery.limit = 1
countQuery.addAscendingOrder("createdAt")
countQuery.countObjectsInBackgroundWithBlock({(count:Int32, error:NSError?) -> Void in
//if no any likes are found, else found likes
if count==0 {
self.commentsArray.append("")
}else{
let commentQuery = PFQuery(className: "comments")
commentQuery.whereKey("to", equalTo: object.objectForKey("uuid") as! String)
commentQuery.limit = 1
commentQuery.addDescendingOrder("createdAt")
commentQuery.findObjectsInBackgroundWithBlock({(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
//clean up
//find related object
for object in objects!{
let comment = object.objectForKey("comment") as! String
let by = object.objectForKey("username") as! String
let commentString = by + " " + comment
self.commentsArray.append(commentString)
}
//reload tableView & end spinning of refresher
self.tableView.reloadData()
self.refresher.endRefreshing()
}else {
print(error?.localizedDescription)
}
})
}
})
}
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
}

Querying private database in swift for user details

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!
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.