首页 > 解决方案 > 向集合视图单元添加集合视图会导致内存增长

问题描述

我创建了一个 CollectionView,并在每个 CollectionViewCell 上创建了一个 CollectionView。下面我包含了位于 MainCollectionView 单元格内的 collectionView 的代码。每次我将单元格从一个 collectionView 滑到另一个时,内存都会增长,并且在删除一个单元格后,内存不会被释放。我读过collectionView 对其布局有很强的参考 我不确定这是否是原因。我执行这个错误吗?谢谢你的帮助。

主视图控制器

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FullPageCell.reuseIdentifier, for: indexPath) as? FullPageCell else{
        assertionFailure("Fatal Error FullPageCell not dequed")
        return UICollectionViewCell()
    }
    cell.backgroundColor = UIColor.green
    cell.cellTappedDelegate = self

    return cell
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return numberOfPages
}

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if let cell = cell as? FullPageCell{
            cell.setUpCollectionView()
    }
}

func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if let cell = cell as? FullPageCell{
        cell.collectionView = nil
    }
}

子单元集合视图

    static var reuseIdentifier: String = "FullPageCell"

   var collectionView:UICollectionView? = nil
    weak var cellTappedDelegate:CellTappedDelegate?
    var image:UIImage  = #imageLiteral(resourceName: "Image")

    override init(frame: CGRect) {
        super.init(frame:frame)


        self.setUpCollectionView()
    }

    func setUpCollectionView(){
        let view = self.contentView

        let layout = UICollectionViewFlowLayout()
        layout.minimumLineSpacing = 1
        layout.minimumInteritemSpacing = 1
        layout.scrollDirection = .vertical
        layout.itemSize = CGSize(width: (view.bounds.width - 2)/3, height: (view.bounds.width - 2)/3)

        self.collectionView = UICollectionView(frame:view.bounds, collectionViewLayout: layout)

        guard let collectionView = collectionView else{
            return
        }
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.register(SmallCell.self, forCellWithReuseIdentifier: SmallCell.reuseIdentifier)
        collectionView.backgroundColor = UIColor.white

        self.collectionView?.isPagingEnabled = true

        view.addSubview(collectionView)

        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
        collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SmallCell.reuseIdentifier, for: indexPath) as? SmallCell else{
            assertionFailure("Fatal Error FullPageCell not dequed")
            return UICollectionViewCell()
        }
        cell.backgroundColor = UIColor.yellow
        cell.imageView.image = self.image
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1000
    }

标签: iosmemory-leaksuicollectionviewautomatic-ref-countingretain-cycle

解决方案


不确定这个游乐场是否反映了您正在尝试做的事情,但它会向您展示如何避免每次都创建 collectionView:

import UIKit
import PlaygroundSupport

class InnerCell: UICollectionViewCell {
    let textLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.backgroundColor = .white
        textLabel.layer.borderColor = UIColor.gray.cgColor
        textLabel.layer.borderWidth = 1
        textLabel.textAlignment = .center
        textLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(textLabel)
        NSLayoutConstraint.activate([
            textLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            textLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            textLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
            textLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }
}

class Cell: UICollectionViewCell, UICollectionViewDataSource {

    var data: [Int]! = [] {
        didSet {
            collectionView.reloadData()
        }
    }
    private let collectionView: UICollectionView

    override init(frame: CGRect) {
        let layout = UICollectionViewFlowLayout()
        layout.minimumLineSpacing = 1
        layout.minimumInteritemSpacing = 1
        layout.itemSize = .init(width: 220, height: 220)
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        super.init(frame: frame)
        collectionView.isPagingEnabled = true
        collectionView.backgroundColor = .white
        collectionView.register(InnerCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView.dataSource = self
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(collectionView)
        NSLayoutConstraint.activate([
            collectionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            collectionView.topAnchor.constraint(equalTo: contentView.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! InnerCell
        cell.textLabel.text = String(data[indexPath.item])
        return cell
    }
}

class VC: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    let data = [
        0: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
        1: [6, 4],
        2: [5, 5, 5, 5, 6],
        3: [1, 2, 3, 4, 5, 6, 7]
    ]

    override init(collectionViewLayout layout: UICollectionViewLayout) {
        super.init(collectionViewLayout: layout)
        collectionView.isPagingEnabled = true
        collectionView.register(Cell.self, forCellWithReuseIdentifier: "Cell")
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
        cell.data = data[indexPath.item]
        return cell
    }

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return collectionView.bounds.size
    }

}

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
PlaygroundPage.current.liveView = VC(collectionViewLayout: layout)


推荐阅读