ios - TableView中的CollectionView显示错误的Data swift

标签 ios swift uitableview swift3 uicollectionview

我正在尝试将 CollectionViewTableView 结合起来,所以除了一个我无法自己解决的问题之外,一切正常。

我必须在CollectionViews中加载一些数据,这些数据按照CollectionView所在的TableViewCell的标题进行排序。由于某种原因,每次启动应用程序时,前三个 TableViewCells 都是相同的。如果我垂直滚动一点,它们就会更改为正确的数据。 但也可能会发生这样的情况:在使用它时,有时会显示与另一个 TableViewCell 上的 TableViewCell 相同的数据,如果我稍微滚动一下,问题就会再次得到解决。

我认为问题出在可重用单元上,但我自己找不到错误。我尝试插入一个colletionView.reloadData()并在重用之前将单元格设置为nil,遗憾的是这不起作用。

我的TableViewController

import UIKit
import RealmSwift
import Alamofire
import SwiftyJSON

let myGroupLive = DispatchGroup()
let myGroupCommunity = DispatchGroup()
var channelTitle=""

class HomeVTwoTableViewController: UITableViewController {


var headers = ["LIVE","Channel1", "Channel2", "Channel3", "Channel4", "Channel5", "Channel6"]

override func viewDidLoad() {
    super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
     self.navigationController?.navigationBar.isTranslucent = false
   DataController().fetchDataLive(mode: "get")
   DataController().fetchDataCommunity(mode: "get")
}

//MARK: Custom Tableview Headers
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return headers[section]
}

//MARK: DataSource Methods
override func numberOfSections(in tableView: UITableView) -> Int {
    return headers.count
}

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

//Choosing the responsible PrototypCell for the Sections
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
        print("TableViewreloadMain")
        cell.collectionView.reloadData()
        return cell
    }
    else if indexPath.section >= 1 {
        // getting header Titel for reuse in cell
        channelTitle = self.tableView(tableView, titleForHeaderInSection: indexPath.section)!
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
        // anti Duplicate protection
        cell.collectionView.reloadData()

        return cell
    }

    else {
        channelTitle = self.tableView(tableView, titleForHeaderInSection: indexPath.section)!
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
        // anti Duplicate protection
        cell.collectionView.reloadData()

        return cell
    }
}
}
}

我的TableViewCell与`CollectionView

import UIKit
import RealmSwift

var communities: Results<Community>?

class HomeVTwoTableViewCellSmall: UITableViewCell{

//serves as a translator from ChannelName to the ChannelId
var channelOverview: [String:String] = ["Channel1": "399", "Channel2": "401", "Channel3": "360", "Channel4": "322", "Channel5": "385", "Channel6": "4"]
//Initiaize the CellChannel Container
var cellChannel: Results<Community>!

//Initialize the translated ChannelId
var channelId: String = ""

@IBOutlet weak var collectionView: UICollectionView!

 }

 extension HomeVTwoTableViewCellSmall: UICollectionViewDataSource,UICollectionViewDelegate {

//MARK: Datasource Methods
func numberOfSections(in collectionView: UICollectionView) -> Int
{
    return 1
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellSmall", for: indexPath) as? HomeVTwoCollectionViewCellSmall else
    {
        fatalError("Cell has wrong type")
    }
    //removes the old image and Titel
    cell.imageView.image = nil
    cell.titleLbl.text = nil
    //inserting the channel specific data
    let url : String = (cellChannel[indexPath.row].pictureId)
    let name :String = (cellChannel[indexPath.row].communityName)
    cell.titleLbl.text = name
    cell.imageView.downloadedFrom(link :"link")
    return cell
}


//MARK: Delegate Methods

override func layoutSubviews() {
    myGroupCommunity.notify(queue: DispatchQueue.main, execute: {

        let realm = try! Realm()
        //Getting the ChannelId from Dictionary
        self.channelId = self.channelOverview[channelTitle]!

        //load data from Realm into variables
        self.cellChannel = realm.objects(Community.self).filter("channelId = \(String(describing: self.channelId)) ")

        self.collectionView.dataSource = self
        self.collectionView.delegate   = self
        print("collectionView layout Subviews")
        self.collectionView.reloadData()
    })

}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    selectedCommunity = (cellChannel[indexPath.row].communityId)
    let home = HomeViewController()
    home.showCommunityDetail()
}
}

提前致谢。

最佳答案

tl;dr 将 channelTitle 设为单元格上的变量,而不是全局变量。另外,请在 prepareForReuse

上清除它以及其他单元格变量 <小时/>

我在这里可能弄错了,但是您在创建单元格后是否在单元格上设置了channelTitle?正如我所看到的,在你的 viewController 中,你根据标题创建单元格,并且对于每个单元格,你将 TableViewControllerchannelTitle 设置为给定部分的标题。

如果是这种情况,那么 TableViewCell 实际上没有收到任何有关在调用 reloadData() 之前应加载内容的信息。

一般来说,我还建议在您的 HomeVTwoTableViewCellSmall 中实现 prepareForReuse,因为它让您有机会清理任何过时的数据。您可能希望在该方法中将 cellChannelchannelId 设置为空字符串或 nil 之类的操作,因此当重复使用旧单元格时数据一直存在。

<小时/>

另外,我刚刚重新阅读了您的单元格代码,看起来您正在 layoutSubviews 中进行一些关键的初始单元格设置。该方法可能会被多次调用,但实际上您只需要调用它一次(对于它所做的大部分工作)。试试这个:

  • 使用单元上的重用标识符覆盖 init
  • 在该 init 中,添加 self.collectionView.dataSource = selfself.collectionView.delegate = self
  • channelTitle 上添加 didSet
  • 在 viewController 中设置 channelTitle

所以代码看起来像:

var channelTitle: String = "" {
    didSet {
        self.channelId = self.channelOverview[channelTitle]!
        self.cellChannel = realm.objects(Community.self).filter("channelId = \(String(describing: self.channelId)) ")
        self.collectionView.reloadData()
    }
}

这样,您仅在单元​​格更新为新 channel 时才重新加载数据,而不是单元格 View 的每个布局。

<小时/>

抱歉...还有一个补充。我不知道您的 channelTitle 实际上是如何传递的。正如我所看到的,您使用 channelTitle 作为全局变量而不是本地变量。不要那样做!在实现上述代码之前,从当前位置删除 channelTitle 。您会看到一些错误,因为您在 ViewController 中设置它并在单元格中访问它。您想要的是从 ViewController 设置单元格上的 channelTitle (正如我上面概述的那样)。这也解释了为什么您在所有三个单元格中看到相同的数据。基本上,您只设置了一个 channelTitle,并且所有三个单元格都在寻找该全局值来获取其数据。

希望对您有一点帮助!

(此外,您应该能够删除 cellForRowAtIndexPath 方法中的 else if block ,因为它后面的 else block 覆盖了相同的代码。您还可以删除 viewDidLoad,因为它没有执行任何操作,并且通常您应该查看是否可以删除任何 !,因为它们不安全. 使用 ?guardif let 代替)

关于ios - TableView中的CollectionView显示错误的Data swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44757530/

相关文章:

ios - UICollectionView cellForItemAt : won't be called while layoutAttributesForElements are returning values

ios - Swift:NSDateFormatter dateFromString 在设备上返回 nil

ios - 如何让 NSTimer 在满足条件后停止重复

ios - 自动将用户添加到 Swift 中的 Parse 类

Swift 子模块——它们到底是什么

iphone - 在静态 UITableView 中添加新部分

ios - 如何将 .mp4 添加到 uitableviewcell 中的按钮

ios - 在 MPMoviePlayerController 中播放视频时出现 _itemFailedToPlayToEnd 错误

ios - 突出显示整个 UITableviewcell 而不是单元格内的圆形 View

ios - Swift 中的 PFQueryTableViewController 使用 Cloud Code 函数