添加到UIStackView在一个UITableView从后台线程

问题描述 投票:1回答:2

我有一个内部具有水平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())
                }
            }
        }
    }
}

有点难看,因为它有一些深层次的嵌套,但取得了很大的性能影响。

我很高兴与此,直到我向下滚动到我的表视图的底部,并启动滚动回来。我注意到,一些CustomViews都是在堆栈视图中两次当电池正在滚动到视图。一旦电池是充分考虑到堆栈视图纠正自己的大部分时间回到了正确的号码。

在我prepareForReuse我专门打电话请与下列功能:

func resetDescriptionStackView() {
    descriptionStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
}

之前罚款是这一切都在主线程它一直工作。

任何帮助极大的赞赏。我敢肯定,这是因为它只是开始后的头,让我感动的东西到后台线程问题。

ios swift uitableview uistackview
2个回答
1
投票

首先使用多为大/硬后台工作服务的所有装置技术领域质量(例如:发送统计资料,与服务器同步数据的基础上,等等),但是当你想要做不同的队列比主一些快速的工作,然后更新UI正确的方式使用.userInitiated或.utility。此外,我建议使用自己的OperationQueue与背景的Qos之一。 为了让代码更优秀,你可以使用“推迟”的声明(documentation)和独立的代码,以小功能。

如果你想添加子视图一旦你能为你的CustomView和间距添加特殊的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)
           }
       }

希望这将有助于!


0
投票

你的问题是由于表视图细胞重用。

什么情况是,当你向下滚动当前可见的细胞已经跑了他们的后台任务,创造了意见。的时候,他们完成当前可见细胞已经改变以显示当前的数据,但它们仍然是由表视图之前所使用的相同的小区的实例。所以现在二人倒闭将增加欣赏到相同的堆栈视图实例。 (小区前一个闭合已被重新使用和小区后另一种闭合已被重新使用)

你可以做的每个小区创建一个UUID储存于细胞内,如果相等捕捉它在后台任务关闭和测试。如果任务没有结果是不相关的细胞发生了变化呈现另一个可见行。

e.g:

class CustomViewCell: UITableViewCell
{
    private var cellId: String = ""

    // call this method for each cell in cellForItemAt implementation
    func configure(_ items: [Any])
    {
        cellId = UUID() // generates a randomized string

        updateStackView(items)      
    }

    private func updateStackView(_ items: [Any]) {
        let curretCellId = cellId
        DispatchQueue.global(qos: .background).async {
            items.forEach { item in
                if let customViewModel = item as? CustomViewModel {
                    DispatchQueue.main.async {
                        if (self.cellId == currentCellId)
                        {
                            self.myStackView.addArrangedSubview(CustomView(customViewModel))
                        }
                    }
                } else if item is Spacing {
                    DispatchQueue.main.async {
                        if (self.cellId == currentCellId)
                        {
                            self.myStackView.addArrangedSubview(PipeSpacerView())
                        }
                    }
                }
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.