TableviewCell中的Collectionview,数据重复

Collectionview in TableviewCell, data repeat

我的可调整大小的 tablviewCells 中有一个集合视图。 Tableview 在每个 'n' 个部分中有一个单元格。 collectionview 的Datasource 和delegate 设置为tableviewCell。在 tablview 的 cellForRowAt 上有一个 API 调用,结果呈现在每个单元格的 collectionview 上。获取结果后,委托告诉 tableview 已加载 collectionview 并且它应该重新加载该单元格而不调用 API 这次。但问题是我的 collectionview 数据在每 2 个 tableviewCells 之后重复一次。

我知道应该覆盖 prepareForReuse 以消除单元重用问题。我已经在我的 collectionviewCells 中实现了 prepareForReuse 并将我的 label.text 和 imageView.image 设置为 nil。但是我不确定要为我的 tableviewCell 添加什么到 prepareForReuse。

// 表格视图 class

override func viewDidLoad() {
        super.viewDidLoad()

        storiesSections = [....]

        tableView.register(UINib(nibName: "RWFeedTableViewCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
        tableView.estimatedRowHeight = 1
        tableView.rowHeight = UITableView.automaticDimension
    }

override func numberOfSections(in tableView: UITableView) -> Int {
        return storiesSections.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! RWFeedTableViewCell

        if cell == nil {
            cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "reuseIdentifier") as! RWFeedTableViewCell
        }

        cell.delegate = self
        cell.fetchData(feedSection: storiesSections[indexPath.section], indexPath: indexPath)
        return cell
    }

// delegate for tableview reload
func collectionViewDidEnd(updatedFeedSection: FeedSection, indexPath: IndexPath) {
        storiesSections[indexPath.section] = updatedFeedSection
        tableView.beginUpdates()
        tableView.endUpdates()
    }

// TableViewCell class


    override func awakeFromNib() {
        super.awakeFromNib()
        initializeCode()
    }

    func initializeCode() {
        // Set layout
        self.collectionView.collectionViewLayout = RWWaterfallLayout2()

        self.collectionView.register(UINib(nibName: "\(ImageThenTitleViewCell.self)", bundle: nil), forCellWithReuseIdentifier: kImageThenTitleCellID)
        self.collectionView.register(UINib(nibName: "\(LeftImageCell.self)", bundle: nil), forCellWithReuseIdentifier: kLeftImageCellID)
        self.collectionView.contentInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
        self.collectionView.isScrollEnabled = false
        self.collectionView.dataSource = self
        self.collectionView.delegate = self
    }

    func fetchData(feedSection: FeedSection, indexPath: IndexPath)  {

        if feedSection.isLoadComplete {
            return
        }

        if let catID = feedSection.categoryID {

            let urlString = URL(string: <urlString>)

            let urlRequest = URLRequest(url: urlString!)

            let config = URLSessionConfiguration.default
            let session = URLSession(configuration: config)

            let task = session.dataTask(with: urlRequest) { (data, response, error) in

                if error == nil {

                } else {
                    print(error?.localizedDescription as Any)
                }

                guard let responseData = data else {
                    print("Error: did not receive data")
                    return
                }

                do {
                    guard let todo = try JSONSerialization.jsonObject(with: responseData, options: [])as? [String: Any] else {
                        print("error trying to convert data to JSON")
                        return
                    }
                    print("success convert data to JSON")

                    DispatchQueue.main.async {

                        var updatedFeedSection = feedSection
                        updatedFeedSection.storiesArray? = (todo["data"]! as! Array)
                        updatedFeedSection.isLoadComplete = true

                        self.feedSection = updatedFeedSection

                        self.collectionView.reloadData()

                        self.collectionView.performBatchUpdates({

                        }, completion: { (complete) in
                            self.collectionViewHeightConstraint.constant = self.collectionView.collectionViewLayout.collectionViewContentSize.height + self.collectionView.contentInset.top + self.collectionView.contentInset.bottom
                            self.delegate?.collectionViewDidEnd(updatedFeedSection: updatedFeedSection, indexPath: indexPath)
                        })
                    }
                } catch  {
                    print("error trying to convert data to JSON")
                    return
                }

            }
            task.resume()
        }
    }

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

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if self.feedSection == nil {
            return 0
        } else {
            return (self.feedSection?.storiesArray?.count)!
        }
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let indexForTen = indexPath.item%10

        let story = self.feedSection?.storiesArray?[indexPath.item]

        if indexForTen == 0 {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kImageThenTitleCellID, for: indexPath) as! ImageThenTitleViewCell
            cell.setupData(story: story!)
            return cell
        }
        else {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kLeftImageCellID, for: indexPath) as! LeftImageCell
            cell.setupData(story: story!)
            return cell
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()
    }

// 集合视图单元格


    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    func setupData(story: Dictionary<String, Any>){
        self.storyImage.image = nil // reset the image

        let thumbImage = story["image"] as! Dictionary<String, String>

        self.storyTitle.text = story["t"] as? String
        self.storyImage.downloaded(from: (thumbImage["m"])!)

        self.layer.borderColor = UIColor.lightGray.cgColor
        self.layer.borderWidth = 1
        self.layer.cornerRadius = 8
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        storyImage.image = nil
        storyTitle.text = nil
    }

// FeedSection 结构


struct FeedSection {
    var categoryID: String?
    var storiesArray : [Dictionary<String, Any>]?
    var isLoadComplete: Bool

    init(categoryID: String) {
        self.categoryID =  categoryID
        self.storiesArray = []
        self.isLoadComplete = false
    }
}

目前第3个tableviewCell重复第1个tablviewCell的数据。如何避免单元格数据重复?

获取数据后设置UITableView.reloadData()。 并检查您是否设置了 CollectionView.reloadData(),如果是,则删除 UICollectionViewreloadData()。只设置 UITableView.reloadData()

唯一的问题是 TableViewCell 中的 feedSection 对象。它应该在调用 fetchData() 时初始化。如果 isLoadComplete 为真,只需重新加载 collectionView

此外,由于 isLoadComplete 是在 URLSession 的完成处理程序上设置的,我在调用 API 时将其设置为 true。所以在等待响应时不会调用相同的 api 。也许可以为 FeedSection 上的 api 调用和 api 响应事件设置一个枚举。但目前这可行。

func fetchData(feedSection: FeedSection, indexPath: IndexPath)  {

        self.feedSection = feedSection

        if self.feedSection.isLoadComplete {
            self.collectionView.reloadData()
            return
        }

        if let catID = feedSection.categoryID {

            let urlString = URL(string: <urlString>)

            let urlRequest = URLRequest(url: urlString!)

            let config = URLSessionConfiguration.default
            let session = URLSession(configuration: config)

            self.feedSection.isLoadComplete = true
            self.delegate?.collectionViewDidEnd(updatedFeedSection: self.feedSection, indexPath: indexPath)

            let task = session.dataTask(with: urlRequest) { (data, response, error) in

                if error == nil {

                } else {
                    print(error?.localizedDescription as Any)
                }

                guard let responseData = data else {
                    print("Error: did not receive data")
                    return
                }

                do {
                    guard let todo = try JSONSerialization.jsonObject(with: responseData, options: [])as? [String: Any] else {
                        print("error trying to convert data to JSON")
                        return
                    }
                    print("success convert data to JSON")

                    DispatchQueue.main.async {

                        self.feedSection.storiesArray? = (todo["data"]! as! Array)
                        self.feedSection.isLoadComplete = true

                        self.collectionView.reloadData()

                        self.collectionView.performBatchUpdates({

                        }, completion: { (complete) in

                            self.collectionViewHeightConstraint.constant = self.collectionView.collectionViewLayout.collectionViewContentSize.height + self.collectionView.contentInset.top + self.collectionView.contentInset.bottom
                            self.delegate?.collectionViewDidEnd(updatedFeedSection: self.feedSection, indexPath: indexPath)
                        })
                    }
                } catch  {
                    print("error trying to convert data to JSON")
                    return
                }

            }
            task.resume()
        }
    }