【问题标题】:UIViewController inside CollectionViewCell memory problemCollectionViewCell里面的UIViewController内存问题
【发布时间】: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() 方法中删除了子视图。

请帮我找出问题。

【问题讨论】:

    标签: ios swift uiviewcontroller uicollectionview uicollectionviewcell


    【解决方案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 上添加新的。

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

    【讨论】:

      猜你喜欢
      • 2011-07-23
      • 2010-10-11
      • 2011-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多