0

I want to fetch data using API request.The data is fetch using SwiftyJson and Alamofire. The problem is that the data is fetched but view gets loaded before the values are fetched.How can I Solve the problem?My code is as below:

func fetchData(){
    Alamofire.request(favUrl, method: .get, parameters: [:]).responseJSON {
        response in
        if response.result.isSuccess{

            let dataFetched : JSON = JSON(response.result.value!)
            //print(dataFetched)
            let titleDisp = dataFetched["title"].arrayObject as? [String]
            //print(titleDisp)
            self.trackList = dataFetched["track_id"].arrayObject as? [String]

            print(self.trackList)

        }else{
            print("Error \(String(describing: response.result.error))")

        }
    }
}


override func viewDidLoad() {
    super.viewDidLoad()
    fetchData()
 }
  • Are you saying that the view is appearing before the data is loaded? It isn't entirely clear from your description if this is what you are asking? And you mention that you are going to use this data in various parts of your app. Is this part of the problem? Edit your question and enhance the description of the problem. – ryantxr Nov 24 '17 at 03:48
  • The view is appearing before data is loaded.I want the data fetched to be loaded first. – Geethanjali Reddy Nov 24 '17 at 03:59
  • What kind of places are you going to display this data. such as tableview, imageview – GayashanK Nov 24 '17 at 04:14
  • The data fetched is an array.I will be using it in textViews and even in calculating heights of views and many more. – Geethanjali Reddy Nov 24 '17 at 04:16
  • All there calculating things need to be done at the end of this method as I explained below – GayashanK Nov 24 '17 at 04:19

2 Answers2

1

It is important to understand that apps run multiple threads. The main thread, also called the UI thread, performs the actions for the visible parts of the app, including showing views, reacting to buttons and so on.

You cannot block the Main thread.

When you make calls to external resources like API calls or loading external images, those get executed on a separate thread. That thread is independent of the main thread. Neither thread waits for the other. The app will still react to buttons while the data is loading. What you are asking for is to prevent showing the view until the data is loaded. You can do this, but you must understand that this could take time depending on your network connection. There are two approaches you can take.

  1. Transition to the view that shows the data but put a "Loading" element on the screen until the data loads then remove the "Loading" element then redisplay the view with the data.

  2. Load the data before you show the view. Make the previous view load the data then segue to the view that has to show the data.

You must also decide if this data loads ONCE or every time the view is displayed. By placing the call in viewDidLoad, the API call will only happen once until the app is restarted. If you want the data to load every time the screen is shown, put the call in viewWillAppear.

// Approach #1
func fetchData(){

    self.showSpinner() 

    Alamofire.request(favUrl, method: .get, parameters: [:]).responseJSON {
        response in
        self.hideSpinner() 
        if response.result.isSuccess {

            let dataFetched : JSON = JSON(response.result.value!)
            //print(dataFetched)
            let titleDisp = dataFetched["title"].arrayObject as? [String]
            //print(titleDisp)
            self.trackList = dataFetched["track_id"].arrayObject as? [String]

            print(self.trackList)

            // Actually update the relevant screen elements here.

        } else {
            print("Error \(String(describing: response.result.error))")
        }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    //fetchData()
}

override func viewWillAppear() {
    super.viewWillAppear()
    fetchData()
}

func showSpinner() {
    // IMPLEMENT ME
}
func hideSpinner() {
    // IMPLEMENT ME
}
ryantxr
  • 4,119
  • 1
  • 11
  • 25
0

Alamofire mathod runs asynchronously. Not in UIThread.Then you have to reload those views after completion of method run.

As Example - tableview

func fetchData(){
    Alamofire.request(favUrl, method: .get, parameters: [:]).responseJSON {
        response in
        if response.result.isSuccess{

            let dataFetched : JSON = JSON(response.result.value!)
            //print(dataFetched)
            let titleDisp = dataFetched["title"].arrayObject as? [String]
            //print(titleDisp)
            self.trackList = dataFetched["track_id"].arrayObject as? [String]

            print(self.trackList)

            // In here you have to reload, set your uiviews or all calculation

            tableview.reloadData()

        }else{
            print("Error \(String(describing: response.result.error))")

        }
    }
}
GayashanK
  • 1,195
  • 2
  • 13
  • 27