Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
144 views
in Technique[技术] by (71.8m points)

ios - Waiting until an asynchronous call is complete before running the "override" functions of a View Controller (Swift)

I am creating an app that fetches stock data from Alpha Vantage and displays it, as a first attempt at Swift (I usually develop in JS).

More precisely, I have a table view, and each cell has the following labels:

  • "Open" price label
  • "High" price label
  • "Low" price label
  • "Close" price label
  • "Volume" label

This is the custom class I'm using for the cell.

    import UIKit

    class StockChoiceCell: UITableViewCell {

        @IBOutlet weak var openPriceLabel: UILabel!
        @IBOutlet weak var highPriceLabel: UILabel!
        @IBOutlet weak var lowPriceLabel: UILabel!
        @IBOutlet weak var closePriceLabel: UILabel!
        @IBOutlet weak var volumeLabel: UILabel!

    }

I have an asynchronous function that successfully retrieves the desired data from Alpha Vantage and returns [DataPoint], where DataPoint is a struct that contains the open, high, low and close prices, as well as the volume. I say successful, as I use the function in another facet of the app without issues.

That function resembles:

func retrieveDataFromAPI (tic: String, completion: @escaping ([DataPoint])->()) {

// Fetch stuff

// Pack it under the DataPoint structure

// ...

completion(arrayOfDataPoints)

}

Here is the issue.

Due to the asynchronous nature of the function, I do not know how to make the application "wait" for the data fetching to complete before running:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! StockChoiceCell

        // ... Setting stuff, etc.

        return cell
    } 

I searched online, trying primarily the following two posts, as one of my attempts consisted of nesting the asynchronous function within another synchronous function:

If this were JS, I'd immediately use a Promise. But Swift is new to me, and I am still exploring how asynchronous functions work in the language.

Thank you!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Due to the asynchronous nature of the function, I do not know how to make the application "wait" for the data fetching to complete before running cellForRowAtIndexPath

Well, cellForRowAtIndexPath will automatically "not execute", when there are no data supplied to the table view. Remember that this is a table view data source method. You don't get to call it directly. So just implement cellForRowAtIndexPath as you would normally. If numberOfRowsInSection returns 0, then cellForRowAtIndexPath would not be called, would it?

I would imagine you have implemented numberOfRowsInSection with a line like this:

return dataSource.count

where dataSource is a property of your VC, of type [DataPoint]. Initially, set this dataSource property to an empty array:

var dataSource = [DataPoint]()

And when the table view loads, it will display nothing, because the data has not been fetched. Now in viewDidLoad, we call this async function to fetch the data:

retrieveDataFromAPI(tic: "some string") {
    dataFetched in
    DispatchQueue.main.async {
        self.dataSource = dataFetched
        self.tableView.reloadData() // this calls the table view data source methods again
    }
}

At the time you call reloadData, dataSource will no longer be empty, and cellForRowAtIndexPath will be called for the appropriate index paths.


Note that there is PromiseKit for Swift, which you may or may not find familiar.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...