I have a tableView where I insert 20 rows with delay using DispatchQueue method. First 10 rows appear fine. Problem starts with 11th one when Xcode begins to dequeue reusable rows. In simulator it looks like it starts to insert by 2 rows nearly at the same time (11th+12th, then 13th+14th).
I wonder why is that. Do DispatchQueue and tableView.dequeueReusableCell methods conflict? And if yes how to organize things properly?
var numberOfCells = 0
//My TableView
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TextCell")! as UITableViewCell
return cell
}
//Function that inserts rows
func updateTableView(nextPassageID: Int) {
for i in 0...numberOfCells - 1 {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(i)) {
self.numberOfCells += 1
let indexPath = IndexPath(row: i, section: 0)
self.tableView.insertRows(at: [indexPath], with: .fade)
}
}
}
Your code didn't work for me. May be you missed something to mention in your question. But with the information that I understood, I did some modification and now it runs (tested in iPhone X) as expected. Following is the working full source code.
import UIKit
class InsertCellViewController: UIViewController, UITableViewDataSource {
var dataArray:Array<String> = []
let reusableCellId = "AnimationCellId"
var timer = Timer()
var index = -1
@IBOutlet weak var tableView: UITableView!
// UIViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: reusableCellId)
tableView.separatorStyle = .none
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateTableView()
}
// MARK : UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reusableCellId)!
cell.textLabel?.text = dataArray[indexPath.row]
return cell
}
// Supportive methods
func updateTableView() {
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(updateCounting), userInfo: nil, repeats: true)
}
@objc func updateCounting(){
if index == 19 {
timer.invalidate()
}
index += 1
let indexPath = IndexPath(row: index, section: 0)
self.tableView.beginUpdates()
self.dataArray.append(String(index))
self.tableView.insertRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
}
}
I think using a Timer
is the better solution in your use case:
private var cellCount = 0
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellCount
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Cell \(indexPath.row)"
return cell
}
func addCells(count: Int) {
guard count > 0 else { return }
var alreadyAdded = 0
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] t in
guard let self = self else {
t.invalidate()
return
}
self.cellCount += 1
let indexPath = IndexPath(row: self.cellCount - 1, section: 0)
self.tableView.insertRows(at: [indexPath], with: .fade)
alreadyAdded += 1
if alreadyAdded == count {
t.invalidate()
}
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
addCells(count: 20)
}
Try to place code inside DispatchQueue.main.asyncAfter
in
self.tableView.beginUpdates()
self.tableView.endUpdates()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.