UICollectionView reloadSection 不会从视图层次结构中删除旧视图

Posted

技术标签:

【中文标题】UICollectionView reloadSection 不会从视图层次结构中删除旧视图【英文标题】:UICollectionView reloadSection does not remove old views from view hierarchy 【发布时间】:2017-01-02 12:24:58 【问题描述】:

UICollectionView 在重新加载部分时不会从视图层次结构中删除可重用视图。这会给UIAutomation 带来问题。

我创建了一个简单的应用程序,它使用UICollectionView 并显示页眉、页脚和单元格。点击“Reload”时,collectionView 会显示不同数量的单元格。请参考下图。

启动应用时,它会显示 2 个单元格。第一次点击“Reload”显示8 cells,第二次点击“Reload”显示18 cells。第三次点击“重新加载”显示 2 个单元格。现在,如果我们使用Xcode View debugger 调试视图,当禁用“仅显示显示的视图”时,它会在视图层次结构中显示多个单元格。参考下图:

这在UIAutomation 中产生了获取元素的问题。我不确定我的实施有什么问题。

下面是我的控制器代码:

struct CellData 
    var title: String
    var value: String


class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 

    @IBOutlet var collectionView: UICollectionView!
    private var data: [CellData]!
    private var data1: [CellData]!
    private var data2: [CellData]!
    private var data3: [CellData]!
    private var reloadIndex = 1
    private var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.data1 = [
            CellData(title: "Cell Title 1", value: "Value 1"),
            CellData(title: "Cell Title 2", value: "Value 2")]
        self.data = self.data1

        self.data2 = [
            CellData(title: "Cell Title 1", value: "Value 1"),
            CellData(title: "Cell Title 2", value: "Value 2"),
            CellData(title: "Cell Title 3", value: "Value 3"),
            CellData(title: "Cell Title 4", value: "Value 4"),
            CellData(title: "Cell Title 5", value: "Value 5"),
            CellData(title: "Cell Title 6", value: "Value 6"),
            CellData(title: "Cell Title 7", value: "Value 7"),
            CellData(title: "Cell Title 8", value: "Value 8")]

        self.data3 = [
            CellData(title: "Cell Title 1", value: "Value 1"),
            CellData(title: "Cell Title 2", value: "Value 2"),
            CellData(title: "Cell Title 3", value: "Value 3"),
            CellData(title: "Cell Title 4", value: "Value 4"),
            CellData(title: "Cell Title 5", value: "Value 5"),
            CellData(title: "Cell Title 6", value: "Value 6"),
            CellData(title: "Cell Title 7", value: "Value 7"),
            CellData(title: "Cell Title 8", value: "Value 8"),
            CellData(title: "Cell Title 9", value: "Value 9"),
            CellData(title: "Cell Title 10", value: "Value 10"),
            CellData(title: "Cell Title 11", value: "Value 11"),
            CellData(title: "Cell Title 12", value: "Value 12"),
            CellData(title: "Cell Title 13", value: "Value 13"),
            CellData(title: "Cell Title 14", value: "Value 14"),
            CellData(title: "Cell Title 15", value: "Value 15"),
            CellData(title: "Cell Title 16", value: "Value 16"),
            CellData(title: "Cell Title 17", value: "Value 17"),
            CellData(title: "Cell Title 18", value: "Value 18")]

        self.collectionView.registerNib(UINib(nibName: "CollectionCell", bundle: nil), forCellWithReuseIdentifier: "CollectionCell")

        self.collectionView.registerNib(UINib(nibName: "SectionHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "SectionHeader")

        self.collectionView.registerNib(UINib(nibName: "SectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "SectionFooter")
    

    @IBAction func reload() 
        self.activityIndicator.center = self.view.center
        self.view.addSubview(self.activityIndicator)
        self.activityIndicator.startAnimating()
        self.view.userInteractionEnabled = false

        let waitTime = 2 * Double(NSEC_PER_SEC)
        let dispatchTime = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), Int64(waitTime))
        dispatch_after(dispatchTime, dispatch_get_main_queue()) 
            self.reloadIndex += 1

            if self.reloadIndex > 3 
                self.reloadIndex = 1
            
            switch self.reloadIndex 
            case 2:
                self.data = self.data2
                break
            case 3:
                self.data = self.data3
                break
            default:
                self.data = self.data1
            
            self.collectionView.reloadSections(NSIndexSet(index: 0))
            //self.collectionView.reloadData()

            self.activityIndicator.stopAnimating()
            self.activityIndicator.removeFromSuperview()
            self.view.userInteractionEnabled = true
        
    

    @IBAction func print() 
        printViewHierarchyInJSON(self.view)
    

    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return self.data.count
    

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 

        let compatibleCell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionCell", forIndexPath: indexPath)
        (compatibleCell as? CollectionCell)?.setData(self.data[indexPath.item])
        return compatibleCell
    

    func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView 

        var supplementaryView = UICollectionReusableView()

        switch kind 
        case UICollectionElementKindSectionHeader:
            supplementaryView = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "SectionHeader", forIndexPath: indexPath)

        case UICollectionElementKindSectionFooter:
            supplementaryView = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionFooter, withReuseIdentifier: "SectionFooter", forIndexPath: indexPath)

        default:
            break
        

        return supplementaryView
    


    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 
        return CGSizeMake(collectionView.bounds.size.width, 50)
    

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize 
        return CGSizeMake(collectionView.bounds.size.width, 104)
    

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize 
        return CGSizeMake(collectionView.bounds.size.width, 86)
    

我已在dropbox 上上传了此示例应用程序。

提前谢谢你。

【问题讨论】:

发布 UICollectionView "cellForItemAt" 代码 我为项目添加了 Dropbox 链接。这是:dropbox.com/s/gp20x3zz15f0vqx/CollectionViewDemo.zip?dl=0 【参考方案1】:

因为每次重新加载不同的元素集:

self.reloadIndex += 1

if self.reloadIndex > 3 
    self.reloadIndex = 1


switch self.reloadIndex 
case 2:
    self.data = self.data2        
case 3:
    self.data = self.data3        
default:
    self.data = self.data1

【讨论】:

以上是关于UICollectionView reloadSection 不会从视图层次结构中删除旧视图的主要内容,如果未能解决你的问题,请参考以下文章

如何滚动另一个 UICollectionView 下方的 UICollectionView?

UICollectionView 单元内部已加载,但 UICollectionView 未显示

UICollectionView 断言失败 -[UICollectionView _updateWithItems:tentativelyForReordering:]

UITableviewCell 中的 UICollectionView。添加约束后,UICollectionView 不显示

将标题添加到 UICollectionView,而不是 UICollectionView 的部分

嵌套垂直 UICollectionView 和动态高度