In our app we populate a table view dynamically from a server.
When scrolling it the table lags.
So I created a Dispatch queue:
var queue = DispatchQueue(label: "myqueue")
Then in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell method I did:
queue.async {
DispatchQueue.main.async {
cell.placeIconView.layer.cornerRadius = cell.placeIconView.frame.width / 2
cell.placeIconView.clipsToBounds = true
}
let poiImgs = HttpResponseHolder.shared.POIS[indexPath.row].imagesUrls
if poiImgs!.count > 0 {
let url = URL(string: poiImgs![0])
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
cell.placeIconView.image = UIImage(data: data!)
}
}
if poiImgs?.count == 0 && HttpResponseHolder.shared.POIS[indexPath.row].detailsOnWeb == false {
DispatchQueue.main.async {
cell.placeIconView.image = UIImage(named: "img_poi_placeholder")
}
}
if poiImgs?.count == 0 && HttpResponseHolder.shared.POIS[indexPath.row].detailsOnWeb == true {
DispatchQueue.main.async {
cell.placeIconView.image = UIImage(named: "url_img_placeholder")
}
}
DispatchQueue.main.async {
cell.dotImgView.isHidden = true
}
if self.showCrowdingState == true {
let crowdIndex = HttpResponseHolder.shared.POIS[indexPath.row].crowdingLevel
DispatchQueue.main.async {
cell.dotImgView.isHidden = false
}
switch crowdIndex {
case 1:
// green
DispatchQueue.main.async {
cell.dotImgView.image = UIImage(named: "greenDot")
}
case 2:
// yellow
DispatchQueue.main.async {
cell.dotImgView.image = UIImage(named: "yellowDot")
}
case 3:
// green
DispatchQueue.main.async {
cell.dotImgView.image = UIImage(named: "redDot")
}
default:
break
}
} else {
DispatchQueue.main.async {
cell.dotImgView.image = nil
}
}
}
As you can see I put my cell configuration within a background thread (and pushed back the UI updates in the Main thread).
This fixed the lag but when I scroll the table view load its content with a delay.
Did I mistake something?
cellForRow
will execute on the main-queue. You are switching queues a lot inside of it, which will also have an affect on speed. As a general approach, you should either have the models to populate the cells available before you display cells (and display a loading indicator until enough models are ready to populate the view port) or you should allow cells to load their own models asynchronously after they have already been displayed. There are many frameworks and architectures or libraries that allow such an approach, such as RxSwift + MVVM or IGListKit. – erik_m_martens