0

I'm fairly new to iOS programming and I'm having trouble when using variables from a completion statement. I have included the code below, I'm not sure why when I store the completion variables in a dataType array it seems to only return blank strings.

Note: Completion data is called in the loadSampleStockData function and it is later suppose to be returned to cells in func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

Thanks for any help that can be provided!

import UIKit

class dashboardViewController: DefaultViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var balanceLabel: UILabel!

    var stocks = [stockData]()
    let stock = stockinfo()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.reloadData()
        loadSampleStockData()
        user.newUser() // Move to login function when login and registration is implemented

        //Sets the Balance Label on Dashboard
        balanceLabel.text = "$" + String(format: "%.2f", user.getBalance())
    }

    func loadSampleStockData () {

        var stock1: stockData = stockData(name: "", askPrice: "", percentageChange: "", stockTicker: "")
        var stock2: stockData = stockData(name: "", askPrice: "", percentageChange: "", stockTicker: "")
        var stock3: stockData = stockData(name: "", askPrice: "", percentageChange: "", stockTicker: "")

        stock.getInfo("FB") {(name, price, change) in dispatch_async(dispatch_get_main_queue(),{
            stock1 = stockData(name: name, askPrice: price, percentageChange: change, stockTicker: "FB")
            stocks.append(stock1)
        })
        }

        stock.getInfo("MSFT") {(name, price, change) in dispatch_async(dispatch_get_main_queue(),{
            stock2 = stockData(name: name, askPrice: price, percentageChange: change, stockTicker: "MSFT")
            stocks.append(stock2)
        })
        }

        stock.getInfo("APPL") {(name, price, change) in dispatch_async(dispatch_get_main_queue(),{
            stock3 = stockData(name: name, askPrice: price, percentageChange: change, stockTicker: "APPL")
            stocks.append(stock3)
        })
        }
        print(stocks.count)
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return stocks.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cellIdentifier = "stockViewCell"

        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! stockTableViewCell

        let stock = stocks[indexPath.row]

        cell.stockName.text = stock.name
        cell.stockPercentage.text = stock.percentageChange
        cell.stockDollarChange.text = stock.askPrice
        cell.stockTicker.text = stock.stockTicker

        return cell
    }
}

1 Answers1

1

Because stocks += [stock1, stock2, stock3] occurs before your async calls have set stock1...3 to anything.

The creation of stocks should be done in a completion handler.

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • Thanks for the response, might be an ignorant question but if I initiate stocks within the completion handler wouldn't I not be able to call them in another completion handler and therefore the other functions because of variable scope? As I may be misunderstanding would you mind providing a code snippet? Thanks for your help – Mark Gong-Guy Jul 05 '16 at 17:12
  • You'll need a shared state, such as the instance variable you have here. Each completion handler will add to the array asynchronously, and the main thread will wait until they're all done – Alexander Jul 05 '16 at 17:13
  • Thanks so much for your patience and taking the time to help me through this. I've tried to add to the data to 'stocks' in the completion handler. How would I go about passing 'stocks' into the completion handlers. I have made my changes above, am I going about this wrong and if so would you mind providing me a code snippet. Thanks so much for your help I will continue to google and read documentation – Mark Gong-Guy Jul 05 '16 at 17:36
  • You don't pass `stocks` in, the closure will automatically "capture" a reference to it. I can't really offer any code snippets, as I haven't worked with multithreaded Swift yet. You need to put a lock/semaphore/mutex around the `.append()` instruction, to make prevent race conditions. – Alexander Jul 05 '16 at 18:03