简体   繁体   English

TableView中的CollectionView显示错误的数据快速

[英]CollectionView in TableView displays false Data swift

I'm trying to combine a CollectionView with a TableView , so fare everything works except one problem, which I cant fix myself. 我正在尝试将CollectionViewTableView结合使用,因此除了一个问题(我无法自行解决)之外,一切正常。

I have to load some data in the CollectionViews which are sorted with the header of the TableViewCell where the CollectionView is inside. 我必须在CollectionViews加载一些数据,这些数据按照其中CollectionViews其中的TableViewCell的标题排序。 For some reason, every time I start the app, the first three TableViewCells are identical. 由于某种原因,每次我启动该应用程序时,前三个TableViewCells都是相同的。 If I scroll a little bit vertically, they change to the right Data. 如果我垂直滚动一点,它们将变为正确的数据。 But it can also happen that while using it sometimes displays the same Data as in on TableViewCell another TableViewCell , here again the problem is solved if I scroll a little. 但是也可能发生,有时在使用它时会在另一个TableViewCell上显示与在TableViewCell上相同的数据,在这里,如果我稍微滚动一下,问题就可以解决了。

I think the problem are the reusableCells but I cant find the mistake myself. 我认为问题是reusableCells,但我自己找不到错误。 I tried to insert a colletionView.reloadData() and to set the cells to nil before reusing, sadly this didn`t work. 我试图插入colletionView.reloadData()并将单元格设置nil然后再使用,可惜这没有用。

My TableViewController 我的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
    }
}
}
}

My TableViewCell with `CollectionView 我的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()
}
}

Thanks in advance. 提前致谢。

tl;dr make channelTitle a variable on your cell and not a global variable. tl; dr将channelTitle为单元上的变量,而不是全局变量。 Also, clear it, and your other cell variables, on prepareForReuse 另外,在prepareForReuse上清除它以及其他单元格变量


I may be mistaken here, but are you setting the channelTitle on the cells once you create them? 在这里我可能会弄错了,但是一旦创建了单元,您是否要在单元上设置channelTitle As I see it, in your viewController you create cells based on your headers, and for each cell you set TableViewController 's channelTitle to be the title at the given section. 正如我所看到的,在viewController中,您基于标题创建单元格,并为每个单元格将TableViewControllerchannelTitle设置为给定部分的标题。

If this is the case, then the TableViewCell actually isn't receiving any information about what it should be loading before you call reloadData() . 如果是这种情况,则在调用reloadData()之前, TableViewCell实际上没有收到任何有关应加载的信息。

In general, I would also recommend implementing prepareForReuse in your HomeVTwoTableViewCellSmall , since it will give you a chance to clean up any stale data. 通常,我还建议您在HomeVTwoTableViewCellSmall实现prepareForReuse ,因为这将使您有机会清理所有过时的数据。 Likely you would want to do something like set cellChannel and channelId to empty strings or nil in that method, so when the cell is reused that old data is sticking around. 您可能想要在该方法中执行将cellChannelchannelId设置为空字符串或nil ,因此,当单元被重用时,旧数据会残留在周围。


ALSO, I just reread the cell code you have, and it looks like you're doing some critical initial cell setup in layoutSubviews . 另外,我只是重新读取了您拥有的单元格代码,看起来您在layoutSubviews进行了一些关键的初始单元格设置。 That method is going to be potentially called a lot, but you really only need it to be called once (for the majority of what it does). 该方法可能会被调用很多,但实际上您只需要调用它一次(对于它的大部分工作)。 Try this out: 试试看:

  • override the init with reuse identifier on the cell 使用单元上的重用标识符覆盖init
  • in that init, add self.collectionView.dataSource = self and self.collectionView.delegate = self 在该init中,添加self.collectionView.dataSource = selfself.collectionView.delegate = self
  • add a didSet on channelTitle channelTitle上添加didSet
  • set channelTitle in the viewController 在viewController中设置channelTitle

So the code would look like: 因此,代码如下所示:

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

This way you're only reloading your data when the cell is updated with a new channel, rather than every layout of the cell's views. 这样,您仅在使用新通道更新单元格时才重新加载数据,而不是单元格视图的每个布局。


Sorry... one more addition. 抱歉,还有另外一个。 I wasn't aware of how your channelTitle was actually being passed. 我不知道您的channelTitle实际上是如何传递的。 As I see it, you're using channelTitle as a global variable rather than a local one. 正如我所看到的,您正在使用channelTitle作为全局变量,而不是局部变量。 Don't do that! 不要那样做! remove channelTitle from where it is currently before implementing the code above. 在实施上述代码之前,请从当前位置删除channelTitle You'll see some errors, because you're setting it in the ViewController and accessing it in the cell. 您会看到一些错误,因为您是在ViewController中进行设置并在单元格中对其进行访问。 What you want is to set the channelTitle on the cell from the ViewController (as I outlined above). 您想要的是在ViewController的单元格上设置channelTitle (如上所述)。 That also explains why you were seeing the same data across all three cells. 这也解释了为什么在所有三个单元格中看到相同的数据。 Basically you had set only ONE channelTitle and all three cells were looking to that global value to fetch their data. 基本上,您只设置了一个channelTitle并且所有三个单元都希望使用该全局值来获取其数据。

Hope that helps a little! 希望能有所帮助!

(also, you should be able to remove your else if block in the cellForRowAtIndexPath method, since the else block that follows it covers the same code. You can also delete your viewDidLoad, since it isn't doing anything, and you should, as a rule, see if you can get rid of any ! 's because they're unsafe. Use ? or guard or if let instead) (同样,您应该能够删除cellForRowAtIndexPath方法中的else if块,因为它后面的else块包含相同的代码。您还可以删除viewDidLoad,因为它没有做任何事情,因此您应该规则,看看您是否可以摆脱任何! ,因为它们不安全。请使用?guardif let代替)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM