[英]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. 我正在尝试将
CollectionView
与TableView
结合使用,因此除了一个问题(我无法自行解决)之外,一切正常。
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中,您基于标题创建单元格,并为每个单元格将
TableViewController
的channelTitle
设置为给定部分的标题。
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. 您可能想要在该方法中执行将
cellChannel
和channelId
设置为空字符串或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:
试试看:
self.collectionView.dataSource = self
and self.collectionView.delegate = self
self.collectionView.dataSource = self
和self.collectionView.delegate = self
didSet
on channelTitle
channelTitle
上添加didSet
channelTitle
in the 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,因为它没有做任何事情,因此您应该规则,看看您是否可以摆脱任何!
,因为它们不安全。请使用?
或guard
或if let
代替)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.