I’ve received an array object from the server, and then I want to download images with one property on that object. then I want to update UI with array objects and images (view model). I’m downloading images on a background thread, but I’m getting images with delay and the object doesn’t fills at all, whats I’m doing wrong?
func presentCoinse(_ list: Home.Models.CoinseListResponse) {
var coins = [Home.Models.coinsViewModel]()
for item in list {
getImage(symbol: item.symbol) { image in
let i = Home.Models.coinsViewModel(image: image,
symbol: item.symbol,
name: item.name,
buyPrice: item.buyPrice,
sellPrice: item.sellPrice,
change24Hource: item.symbol)
coins.append(i)
}
}
viewController?.displayCoinsList(viewModel: coins)
}
private func getImage(symbol: String, complation: @escaping(_ image: Data?) -> Void) {
queue.async {
if let url = URL(string: "(CDN_URL)(symbol).png") {
let data = try? Data(contentsOf: url)
DispatchQueue.main.async {
complation(data)
}
}
}
}
2
Answers
Pay attention that you’re setting coins to empty list, and then you call displayCoinstList with that empty list. the list is appened and updated asyncronically.
You should trigger the view controller to reload the coins list when it’s ready. I’d make the coins list prior going to fetecg the images, and then upon receiving the images – the UIImageView will render itself.
What you did is equivalent to:
The
getImage
method contains async operations, in this situation the closure will be called after the return of the method.And, the method
displayCoinsList(viewModel:)
is called before every asyncgetImage
.You can use the DispatchGroup class.
NOTE: In
getImage
Method is required to callcomplation
In every condition. If you forgot to call it the DispatchGroup can’t receive a notify and you’ll be blocked.