CollectionViewCell里面的UIViewController内存问题

Posted

技术标签:

【中文标题】CollectionViewCell里面的UIViewController内存问题【英文标题】:UIViewController inside CollectionViewCell memory problem 【发布时间】:2018-10-26 14:24:12 【问题描述】:

我在 UICollectionViewCell 中显示 UIViewController。每页一个单元格。问题是当我滑动到下一页时,内存会不断增加并且永远不会回来。

这里是相关代码。

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let newsVC: NewsTableVC = 
        return storyboard?.instantiateViewController(withIdentifier: "NewsListVC")
        () as! NewsTableVC

    let cell = pagerCollectionView.dequeueReusableCell(withReuseIdentifier: "PageCollectionViewCell", for: indexPath) as! PageCollectionViewCell

    //Wraping ViewController in CollectionView Cell
    return wrapAndGetCell(viewColtroller: newsVC, cell: cell)



func wrapAndGetCell(viewColtroller: UIViewController, cell: PageCollectionViewCell) -> PageCollectionViewCell
    //setting tag to remove view when it's being reused
    viewColtroller.view.tag = PageCollectionViewCell.SUBVIEW_TAG
    addChild(viewColtroller)
    viewColtroller.view.frame = cell.contentView.bounds
    cell.contentView.addSubview(viewColtroller.view)
    viewColtroller.didMove(toParent: self)
    return cell

这里是 collectionViewCell 类

class PageCollectionViewCell: UICollectionViewCell 

    static let SUBVIEW_TAG: Int = 1000

    override func prepareForReuse()
        super.prepareForReuse()
        let subViews = self.contentView.subviews
        for subView in subViews
            if subView.tag == PageCollectionViewCell.SUBVIEW_TAG
                subView.removeFromSuperview()
                print("subView removed")
            
        
    

我想问题在于在每个单元格中添加子视图,但我也在 perpareForReuse() 方法中删除了子视图。

请帮我找出问题。

【问题讨论】:

【参考方案1】:

问题在于,每次单元格出列时,您都会创建一个新的NewsTableVC。您需要做的只是重复使用相同的视图控制器,而不是每次获得一个单元格时都创建一个新的视图控制器。

创建一个[NewsTableVC] 类型的数组,然后这样做:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let newsVC = self.newsVCArray[indexPath.item]

    let cell = pagerCollectionView.dequeueReusableCell(withReuseIdentifier: "PageCollectionViewCell", for: indexPath) as! PageCollectionViewCell

    //Wraping ViewController in CollectionView Cell
    return wrapAndGetCell(viewColtroller: newsVC, cell: cell)


这应该可以解决您的内存问题,但是创建将 viewController 的视图添加为 collectionViewCell 子视图似乎是一件奇怪的事情。除非您有充分的理由这样做,否则我建议您只使用 PageCollectionViewCell,而完全忘记 NewsTableVC

我不知道您要完成什么,但很难想象以这种方式使用 collectionViewCell 的场景。

【讨论】:

感谢@LulzCow 它解决了我的问题。基本上我需要在 CollectionView 中显示不同类型的 UIViewControllers。我不能将每个 UIVC 都设为 CollectionViewCell,因为它们在其他地方被重用,这就是我这样做的原因(包装在 CollectionViewCell 中)。如果您认为知道其他更好的方法,请告诉我。【参考方案2】:

我认为这是问题

addChild(viewColtroller)  //1
viewColtroller.view.frame = cell.contentView.bounds
cell.contentView.addSubview(viewColtroller.view)
viewColtroller.didMove(toParent: self)

(1*) self (UIViewController) 强烈保留“子”ViewController

当您 prepareForReuse 单元格时,您只是从层次结构中删除“childViewController”视图,但“childViewController”本身仍由 UIViewController(父级)保留。

当您将一个新单元格出列时,您会重复该过程,创建一个新子单元并将其添加到父单元,而不会删除前一个单元

viewController.removeFromParentViewController()

,所以孩子不会被释放。这增加了每个单元格出列时的内存(实际上每个新的 childViewController 添加到父级)。

确认这一点的一个好方法是在“子”视图控制器的 deinit 方法上放置一个断点。

  deinit 
// Breakpoint here
print("DEINIT")

注意:这里的打印是必需的,空方法不会捕获断点。

另外,要调试它,您可以在添加新子之前打印 childViewControllers

print(self.childViewControllers)

因此,在简历中,这里的问题是 cildViewControllers 被“父级”保留,并且您在每个 dequeue 上添加新的。

希望对您有所帮助,对于回复的长度感到抱歉。

【讨论】:

以上是关于CollectionViewCell里面的UIViewController内存问题的主要内容,如果未能解决你的问题,请参考以下文章

CollectionView 里面的 CollectionView | CollectionViewCell 自动布局错误

CollectionViewCell 顶部的按钮使 collectionView 停止滚动

如何为自定义 TableViewCell 和 CollectionView Cell 使用一个 UIView。?

里面有 TableView 的动态集合视图单元格?

CollectionViewCell 问题。从 .xib 到自定义 collectionviewcell 的故事板转换

插座无法连接到重复内容