3

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?

6
  • What touch the UI has to be done in main thread (like reloadComponents) Commented Mar 3, 2015 at 10:39
  • Sorry, I don't understand your question? Commented Mar 3, 2015 at 10:42
  • dispatch_async(dispatch_get_main_queue(), { () -> Void in self.languagePicker?.reloadAllComponents() }) Commented Mar 3, 2015 at 10:44
  • Larme, this gives me an error: Cannot convert the expressions type (dispatch_queue_tl, () -> Void) to type 'Void' Commented Mar 3, 2015 at 11:07
  • Have you logged out your object and checked that you are actually receiving data? - also where are your languagePicker arrays defined? Commented Mar 3, 2015 at 11:50

3 Answers 3

11
+50

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.
Sign up to request clarification or add additional context in comments.

3 Comments

Let me quickly update my current code. But still I have the issue that the field is empty and get its data after the view is presented. It takes a second until the first selected lessons is shown in the text field.
If you are fetching data in the background, you have to wait to get the data. You can provide loading symbol on the pickerView to indicate a fetch in progress.
thanks for your answer! Is there anyhow a way to "outsource" such data getting functions into a separate file to being able calling these kind of functions from the root controller and store them (in my case with parse local datastore pin) locally? But bedsides that I am much clearer now, thanks!!
0

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()    
})

6 Comments

When I add this, I can not see any changes. The text field is empty and get filled shortly after I can see the view. There is still a delay between the view is shown and the data is loaded into the text field.
If this works but with a delay, Surley the delay is due to the speed of your parsing? perhaps you should load the data before presenting the view.
@Wezly is right. Also, you are starting the load in viewDidAppear: which is quite late (and unusual). Can you measure how much time passes between the call to findObjectsInBackgroundWithBlock and the call to its completion block?
Wezly, this is exact what I want to do! But I don't know how? Please explain!
what I understand now is that if I call the method getLessons() within viewDidLoad instead of viewDidAppear the text appears much faster, but still with a short delay. I really wold like to know if there is a way to load the data before the view is presenting...
|
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.