Search code examples
jsonswiftalamofire

Why can't I get the request result form Alamofire


I can't get the result of Alamofire request.So,I created ouput of an array that I got from json async call.I can't get the resultArray out of dispatch {...}.When I add println to debug the code.The second one appear first before the first one. All i want to resultArray to get the data from Alamofire to display in UIPickerView.Please Help!!!

Here is my code

import UIKit
import Alamofire

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource{

@IBOutlet var venuePicker : UIPickerView?

var resultOld = [String:String]() // i need it to get only value from json

var result : [String]?

let refreshControl = UIRefreshControl()

override func viewDidLoad() {

    if result == nil {
        populateVenues ({ (error, result) -> Void in
            self.result = result as? [String]
            self.venuePicker?.reloadAllComponents()
        })
    }
}

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

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    if result != nil{
        return result!.count// Why i can't use result?.count instead of result!.count
    }
    else{
        return 0
    }
}

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
    if result != nil{
        println(result)
        return result?[row]
    }
    else{
        return "..."
    }
}

func populateVenues(completion : (error: NSError?,result : AnyObject?) -> Void){
    Alamofire.request(.POST, "http://xxxx.xxxx.xxx").responseJSON() {
        (_, _, jsonData, error) in

        if error == nil{
            var venues = JSON(jsonData!)

            for (k, v) in venues {

                self.resultOld[k] = v.arrayValue[0].stringValue
            }

            self.result = self.resultOld.values.array

            completion(error: nil,result: self.result)
        }
        else{
            println("Error!!")
            completion(error: error!,result: nil)
        }
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

Here is my output at console

The 2st result array : []
The 1st result array : [ORIX Kobe Nyusatsu, NPS Sendai Nyusatsu, JU Gunma, KAA Kyoto, JU Ibaraki, USS Gunma, ISUZU Kobe, NAA Osaka Nyusatsu, SMAP Sapporo Nyusatsu, L-Up PKobeNyusatsu, ARAI Sendai, TAA Minami Kyushu, NPS Oyama Nyusatsu, CAA Tokyo, JU Toyama, USS Shikoku, NPS Gifu Nyusatsu, NAA Fukuoka, KCAA Yamaguchi, JU Fukuoka, LAA Kansai, JAA, TAA Kinki, USS Sapporo, JU Miyagi, USS Fukuoka, JU Tokyo]

Please i really need to know what is happening to me and why i can't get the result of async call first.


Solution

  • So asynchronous calls are executed on another thread. Thus, when you call the function populateVenue(), the populateVenue() function is not completing before the println("The 2st result array : \(self.resultArray)" ). If you set up your populateVenue() to have a closure, this won't happen. Example:

    override func viewDidLoad() {
    
       super.viewDidLoad()
    
       populateVenue( { (error, result) -> Void in 
          println("The 2st result array : \(self.resultArray)" )
       })
    }
    
    func populateVenue(completion: (error: NSError?, result: AnyObject?) -> Void) {
        Alamofire.request(.POST, "http://localhost:8080/ws/automobile/global/auction/latest/venues").responseJSON() {
        (_, _, jsonData, error) in
    
           if error == nil {
              // do whatever you need
              // Note that result is whatever data you retrieved
              completion(nil, result)
           } else {
               println("Errror")
               completion(error!, nil)
           }
       }
    }
    

    Edit:

    I am still trying to understand your problem, but this is my best shot. Note that I have no idea what the purpose of resultOld is so I removed it. If you absolutely need it you can add it back in. My design here is to make the properties optional, and return the result in the completion block. Then in viewDidLoad, you can initialize the property array and reload your screen.

    @IBOutlet var venuePicker : UIPickerView?
    
    // Try making this optional so you can tell when the network call is completed
    var result: [String]?
    
    var error = "Error"
    
    let refreshControl = UIRefreshControl()
    
    override func viewDidLoad() {
        if result == nil {
           populateVenues ( { (result) -> Void in
              self.result = result
              self.venuePicker?.reloadAllComponents()
           })
        }
    }
    
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
         if result != nil {
            return result.count
         } else {
            return 0
         }
    }
    
    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
    
        return result[row]
    }
    
    func populateVenues(completion : (result : [String]?) -> Void){
        Alamofire.request(.POST, "http://localhost:8080/ws/automobile/global/auction/latest/venues").responseJSON() {
            (_, _, jsonData, error) in
    
            if error == nil{
                var venues = JSON(jsonData!)
    
                for (k, v) in venues {
    
                    resultOld[k] = v.arrayValue[0].stringValue
    
                }
    
                result = resultOld.values.array
    
                completion(result: result)
            }
            else{
                println("Error!!")
                completion(result: nil)
            }
        }
    }