我有一个UITableViewCell
,里面有一个水平的UIStackView
。创建UIViews
并将其添加到堆栈视图会导致一些性能问题。表格视图的滚动中有一个确定的斑点。我已经在仪器中对其进行了分析,并且调用更新堆栈视图是整个应用程序中第二大的任务。
设置如下。我正在使用MVP,并且在演示者中使用该单元格,在设置单元格时调用updateStackView(with items: [Any])
,并在cellForRowAtIndexPath
方法中设置了该单元格。
我的原始updateStackView(with items: [Any])
如下:
func updateStackView(_ items: [Any]) {
items.forEach { item in
if let customViewModel = item as? CustomViewModel {
myStackView.addArrangedSubview(CustomView(customViewModel))
} else if item is Spacing {
myStackView.addArrangedSubview(PipeSpacerView())
}
}
}
所以这是瓶颈,我决定将一些内容移到后台,如下所示:
func updateStackView(_ items: [Any]) {
DispatchQueue.global(qos: .background).async {
items.forEach { item in
if let customViewModel = item as? CustomViewModel {
DispatchQueue.main.async {
self.myStackView.addArrangedSubview(CustomView(customViewModel))
}
} else if item is Spacing {
DispatchQueue.main.async {
self.myStackView.addArrangedSubview(PipeSpacerView())
}
}
}
}
}
Kinda丑陋,因为它具有一些深层嵌套,但对性能产生了很大影响。
我对此感到满意,直到我向下滚动到表格视图的底部并开始向上滚动。我注意到当单元格滚动到视图中时,某些
CustomViews
在堆栈视图中出现了两次。单元格完全可见后,堆栈视图在大多数情况下会自动更正为正确的数字。在我的
prepareForReuse
中,我确实对以下函数进行了调用:func resetDescriptionStackView() {
descriptionStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
}
一直都在工作,直到一切都在主线程上。
任何帮助,不胜感激。我可以肯定这是一个线程问题,因为当我将内容移至后台时才开始抬起头。
最佳答案
首先,.background服务质量主要用于大型/艰苦的后台工作(例如,发送统计数据,与服务器同步数据库等),但是当您想在不同于main的队列上进行一些快速工作然后更新时UI正确使用.userInitiated或.utility的方式。另外,我建议您将自己的OperationQueue与后台Qos之一一起使用。
为了使代码更好,您可以使用“defer”语句(documentation)并将代码分隔为小函数。
如果要一次添加子视图,则可以为CustomView和Spacing添加特殊ID,然后进行检查。
完整代码:
//For each our CustomView and Spacing we set uniq id to tag property in init of each class.
/// Operation queue that work with our UIStackView
fileprivate lazy var stackViewOperationQueue: OperationQueue = {
let queue = OperationQueue()
queue.name = "StackView OperationQueue"
queue.qualityOfService = .userInitiated
return queue
}()
func updateStackView(_ items: [Any]) {
stackViewOperationQueue.addOperation { [weak self] in
items.forEach { self?.addArrangedSubviewToStackView(by: $0) }
}
}
fileprivate func addArrangedSubviewToStackView(by item: Any) {
var handler: () -> () = {}
defer {
DispatchQueue.main.async {
handler()
}
}
if let customViewModel = item as? CustomViewModel {
handler = { [weak self] in
let viewToAdd = CustomView(customViewModel)
self?.checkAndAddSubviewIfNeeded(viewToAdd)}
}
else if item is Spacing {
handler = { [weak self] in
self?.checkAndAddSubviewIfNeeded(PipeSpacerView()) }
}
}
func checkAndAddSubviewIfNeeded(_ subviewToAdd: UIView) {
if !myStackView.arrangedSubviews.contains(where: { view in return view.tag == subviewToAdd.tag }) {
self.myStackView.addArrangedSubview(subviewToAdd)
}
}
希望对您有所帮助!
关于ios - 从后台线程在UITableView中添加到UIStackView,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54574059/