user1555112
user1555112

Reputation: 1987

ios swift parse: methods with async results

When I go to a viewController I call within my viewDidAppear Method a function:

override func viewDidAppear(animated: Bool) {
    getLessons()
}

This methods loads from parse.com a list of data I want to use in a pickerView. The function itself:

func getLessons(){
        var query = PFQuery(className:"Lesson")
        query.orderByAscending("name")
        query.findObjectsInBackgroundWithBlock {
            (objects: [AnyObject]!, error: NSError!) -> Void in
            if error == nil {

                for object in objects {

                    var name = object["name"] as String

                    self.languagePickerKeys.append(object.objectId)
                    self.languagePickerValues.append(name)

                    self.selectedLanguage.text = self.languagePickerValues.first // set the first lessons name into the text field
                    self.selectedLessonObjectId = self.languagePickerKeys.first // set the first objectId for the lesson

                    self.languagePicker?.reloadAllComponents()

                }
            } else {
                // Log details of the failure
                println("\(error.userInfo)")
            }
        }
        println("getLessons done")
    }

The thing is, that the textfield is empty, as the getLesson() gets the data async and the data is not available to the textfield.

I also tried to put the getLesson into the viewDidAppear method, but this doesn't help me, the textfield is empty anyway.

What can I do, to have the data from the getLessons() method ready and loaded its first value into my textfield when the view is shown to the user?

Upvotes: 3

Views: 1730

Answers (3)

mastro35
mastro35

Reputation: 143

The problem is that findObjectsInBackgroundWithBlock is an asynchronous method, so even if you fire it in the ViewDidLoad you will never know when you will receive the response data and you can't be sure that the data will be ready by the time you view appear.

I think you have just 2 possibility: The first one is to load the data in the previous view controller and then just pass the data that got ready to you view controller.

The second is to use a synchronous method (the findobject method maybe?) and put the call in a method that is fired BEFORE the view appear (like the viewWillAppear: method). But your view will stuck for a moment (I think) while the data is retreiving... However this second solution probably resolve your problem but using synchronous method to retrieve data from a slower data source is usually bad design solution.

D.

Upvotes: 0

saurabh
saurabh

Reputation: 6775

You certainly have to get the data from asyncTask before setting it to pickerView.

Here's the ViewController lifecycle after instantiation:

  • Preparation if being segued to.
  • Outlet setting
  • Appearing and Disappearing.

So, you have two options:

  1. Load the data in previous ViewController and then perform the segue. You need to follow these steps for it.

    a. Create a segue from previous ViewController to your ViewController.

    b. Call the function when you want to go next ViewController which fetches the data, and the end (after getting the data) call performSegueWithIdentifier which will lead to your ViewController.

    c. Set the data in prepareForSegue

    let navigationController = segue.destinationViewController as UINavigationController
    
    navigationController.data = yourData //you got from async call
    

Now when you reach your ViewController, you are sure that your data is present, and you can set it to your pickerView.

  1. If you want to do it in the same ViewController: here's is the lifeCycle of ViewController:life Cycleso you need to call your function in viewDidLoad, and always set your pickerView after completion of the async network call.

Upvotes: 11

Drux
Drux

Reputation: 12670

Make sure that you initiate all changes to the UI from the main thread e.g. like so:

dispatch_async(dispatch_get_main_queue(), {
    selectedLanguage.text = languagePickerValues.first
    self.languagePicker?.reloadAllComponents()    
})

Upvotes: 0

Related Questions