TableviewCell中的Collectionview,数据重复

时间:2019-04-29 05:57:01

标签: swift tableview collectionview reuseidentifier prepareforreuse

我在可调整大小的tablviewCells内部有一个collectionview。 Tableview在每个“ n”个部分中都有一个单元格。数据源和collectionview的委托设置为tableviewCell。在tablview的cellForRowAt上调用了一个API,结果在每个单元的collectionview上呈现。提取结果后,委托将通知tableview加载collectionview,并且应重新加载该单元格,而无需这次调用API。但是问题是我的collectionview数据每隔2个tableviewCells就重复一次。

我知道应该重写prepareForReuse以摆脱单元重用问题。我已经在我的collectionviewCells中实现了prepareForReuse,并将label.text和imageView.image设置为nil。但是我不确定为tableviewCell添加哪些内容来准备prepareForReuse。

// TableView类

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类


    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()
    }

// Collectionview单元格


    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
    }
}

当前第三个tableviewCell重复第一个tablviewCell的数据。如何避免重复单元格数据?

2 个答案:

答案 0 :(得分:1)

唯一的问题是TableViewCell中的feedSection对象。应该在调用fetchData()时对其进行初始化。如果isLoadComplete为true,则只需重新加载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()
        }
    }

答案 1 :(得分:0)

获取数据后设置UITableView.reloadData()。  然后检查是否设置了CollectionView.reloadData(),如果设置为UICollectionView,请删除 reloadData()。只设置UITableView.reloadData()