Search code examples
iosmysqlasynchronousdownloaduipickerview

Swift 1.2 - Why isn't my UIPickerView displaying my data?


I have a UIPickerView which I load with data I download from a MySQL database. The data downloads and fills an array, and then I use that array as the source of data for my pickerView through the delegate methods.

My issue is, everything works fine, except that the pickerView doesn't visibly fill for a good 20 seconds after the array has been filled. I have tried running all sorts of self.view.LayoutIfNeeded() and the like, and have plenty of pickerView.reloadAllComponents() but it still refuses to load visibly. However, if the user taps on the pickerView, or changes it value (even though it is visibly empty), the data suddenly appears. I have tried programmatically selecting each row to try and force it to display, but that hasn't worked.

Here is my code to download the data (which is run on viewDidLoad):

func RetreiveStaff() {
    SetProgramMode()

    self.aUsers = [User]()
    self.pkvUser.reloadAllComponents()

    if self.booCurrentDataVersion == true {

        var url:NSURL = NSURL(string: "http://www.website.com.au/retrievestaff.php")!
        let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in
            if error == nil {
                let dataArray:[AnyObject] = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! [AnyObject]
                for data in dataArray {
                    let dictionary:[String:String] = data as! [String:String]
                    if dictionary["StaffID"] != nil {

                        var newUser:User = User()
                        newUser.name = dictionary["LastName"]! + ", " + dictionary["FirstName"]!
                        newUser.id = dictionary["StaffID"]!.toInt()!
                        self.aUsers.append(newUser)

                        self.pkvUser.reloadAllComponents()
                        self.booDownloadedUsers = true
                    } else {
                        let actionSheet:UIAlertController = UIAlertController(title: "No Users Downloaded", message: "Please ensure a user has been entered in Access and then restart the app.", preferredStyle: UIAlertControllerStyle.Alert)
                        let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {
                            (alertAction:UIAlertAction!) in
                        })
                        actionSheet.addAction(firstAlertAction)
                        self.presentViewController(actionSheet, animated: true, completion: nil)
                    }
                    self.pkvUser.reloadAllComponents()
                }
                println("\(self.aUsers.count) Staff Downloaded")
                self.pkvUser.reloadAllComponents()
                self.view.setNeedsLayout()
            } else {
                let actionSheet:UIAlertController = UIAlertController(title: "Connection Error", message: "\(strAppName) was unable to load data.  Check you are connected to the internet and restart the app.", preferredStyle: UIAlertControllerStyle.Alert)
                let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {
                    (alertAction:UIAlertAction!) in
                })
                actionSheet.addAction(firstAlertAction)
                self.presentViewController(actionSheet, animated: true, completion: nil)
            }
        })

        task.resume()

    }
}

Here are my pickerView delegate methods:

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
    return self.aUsers[row].name
}

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    if count(self.aUsers) > 0 {
        strSelectedUser = self.aUsers[row]
    }
}

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return self.aUsers.count
}

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
    return 1
}

where aUsers is an array of custom 'User' objects that I created.

What do I need to do to get the view to refresh/reload/display the data because I know the data is there. I also understand that I am downloading it asynchronously and that can cause issues like this, but the data downloads almost instantly, and I don't understand why the view won't keep up.

Thanks in advance.


Solution

  • It's probably because you always have to update the UI in main threads, so once you have loaded the data (after you for loop I think) when you want to call the reloadAllComponents() you have to do it like below.

    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
        dispatch_async(dispatch_get_main_queue()) {
            self.pkvUser.reloadAllComponents()
        }
    }