UICollectionViewCell中

UICollectionViewCell中

有一个大问题我几天都解决不了。
我有一个带UICollectionView的UIViewController,其中有3个单元格具有不同的内容。这是我的课:

class PostView: AppViewAddMenu, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
var homeController: FeedController?
var contentArray = [PostContentModel]()
var postInfo: PostModel?
lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    layout.minimumLineSpacing = 3
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.delegate = self
    cv.dataSource = self
    cv.backgroundColor = .white
    return cv
}()

override func setupViewController() {
    collectionView.register(PostViewCell.self, forCellWithReuseIdentifier: "cellId")

    view.addSubview(collectionView)
    view.addConstraintsWithFormat("H:|[v0]|", views: collectionView)
    view.addConstraintsWithFormat("V:|-60-[v0]|", views: collectionView)

    fetchPost(id: postInfo?.id)
}

func fetchPost(id: Int?){
    guard let ID = id else {
        print("ID faild")
        return
    }
    let url: String = "https://FTP.ru/wp-json/mobileApi/v1/post/\(ID)"
    ApiService.sharedInstance.fetchContent(url: url, completion: { (Posts: [PostContentModel]) in
        self.contentArray = Posts
        self.collectionView.reloadData()
    })
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! PostViewCell
    cell.contentArray = contentArray
    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: view.frame.width, height: 1000)
}
}

第一个单元格的想法是从如下站点获取json:[switch, content]。从UICollectionViewCell中的开关值调用不同的函数,这些函数通过addSubview ()在UICollectionViewCell中添加元素。代码如下:
class PostViewCell: UICollectionViewCell {
override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor = .white
    anchor = self.topAnchor
}

var anchor: NSLayoutYAxisAnchor?
var contentArray: [PostContentModel]?{
    didSet{
        for number in contentArray! {
            if(number.switcher == 1) {
                anchor = addTextContent(content: number.content!, bottomAnchor: anchor!)
            }
            if(number.switcher == 2){
                anchor = addImageContent(content: number.content!, bottomAnchor: anchor!)
            }
            if(number.switcher == 3){
                anchor = addCaptionFirst(content: number.content!, bottomAnchor: anchor!)
            }
            if(number.switcher == 4){
                anchor = addButtonLink(content: number.content!, link: number.link!, bottomAnchor: anchor!)
            }
        }
    }
}

func addTextContent(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor{

    let shortContentPost: UILabel = {
        let label = UILabel()
        label.text = content
        label.numberOfLines = 0
        label.font = UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular)
        return label
    }()

    addSubview(shortContentPost)
    shortContentPost.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 15, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)

    return shortContentPost.bottomAnchor
}

func addImageContent(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
    let image: CustomImageView = {
        let image = CustomImageView()
        image.image = UIImage(named: content)
        image.contentMode = .scaleAspectFill
        image.clipsToBounds = true

        return image
    }()


    let imageURL = "https://brodude.ru/wp-content/uploads/" + content.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
    image.loadImageUsingUrlString(urlString: imageURL)

    addSubview(image)
    image.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 15, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 250)

    return image.bottomAnchor
}

func addCaptionFirst(content: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
    let Caption: UILabel = {
        let lb = UILabel()
        lb.text = content
        lb.numberOfLines = 0
        lb.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.semibold)
        return lb
    }()

    addSubview(Caption)
    Caption.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 30, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
    return Caption.bottomAnchor
}

func addButtonLink(content: String, link: String, bottomAnchor: NSLayoutYAxisAnchor) -> NSLayoutYAxisAnchor {
    let button: LinkButton = {
        let bt = LinkButton()
        bt.LinkString = link
        bt.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: UIFont.Weight.semibold)
        bt.setTitle(content, for: UIControlState.normal)
        bt.sizeToFit()
        bt.titleLabel?.numberOfLines = 0
        bt.contentHorizontalAlignment = .left
        bt.setTitleColor(UIColor(red: 0.07, green: 0.32, blue: 0.89, alpha: 1.0), for: UIControlState.normal)
        bt.addTarget(self, action: #selector(linkOut), for: .touchUpInside)
        return bt
    }()
    addSubview(button)
    button.anchor(bottomAnchor, left: self.leftAnchor, bottom: nil, right: self.rightAnchor, topConstant: 20, leftConstant: 15, bottomConstant: 0, rightConstant: 15, widthConstant: 0, heightConstant: 0)
    return button.bottomAnchor
}

该算法运行良好,但问题从更新单元开始。滚动时,使用collectionView.reloadData ()。新的子视图分层在过去,文本变得更胖和堵塞的设备内存。这个过程无限期地继续,直到出现错误为止。
一个问题的例子:,
对不起我的英语。

最佳答案

首先,不要:

addSubview(shortContentPost)

使用:
contentView.addSubview(shortContentPost)

对添加的所有子视图执行此操作。contentView应该保存您的内容。
在你的单元中实现这个prepareForReuse
override func prepareForReuse() {
    super.prepareForReuse()

    let subviews = contentView.subviews
    for subview in subviews {
        subview.removeFromSuperview()
    }
}

这将在重用单元格之前清除单元格内容。
尽管我强烈建议不要动态添加这些子视图,因为这样会丢失很多重用机制。默认情况下,我会将所有视图(标签/图像视图)添加到单元格中,然后使用它们的isHidden属性根据内容隐藏/取消隐藏它们(例如,如果应该显示图像,请将所有其他视图的isHidden设置为true)。对于重用来说,这将是一个性能更好的选择,因为这样一来,每次重用单元格时都不必重新创建UI对象,只需重新配置labels/imageViews的内容即可。

08-05 22:53