TableView 中的 CollectionView 显示 false Data swift
Posted
技术标签:
【中文标题】TableView 中的 CollectionView 显示 false Data swift【英文标题】:CollectionView in TableView displays false Data swift 【发布时间】:2017-06-26 10:19:16 【问题描述】:我正在尝试将 CollectionView
与 TableView
结合起来,所以除了一个我自己无法解决的问题之外,一切正常。
我必须在 CollectionViews
中加载一些数据,这些数据与 CollectionView 所在的 TableViewCell
的标题一起排序。出于某种原因,每次我启动应用程序时,前三个TableViewCells
都是相同的。如果我垂直滚动一点,它们会更改为正确的数据。
但也有可能在使用它时有时会显示与TableViewCell
另一个TableViewCell
相同的数据,如果我稍微滚动一下,问题就会再次解决。
我认为问题出在 reusableCells 但我自己找不到错误。我尝试在重用之前插入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()
提前致谢。
【问题讨论】:
【参考方案1】:tl;dr 在您的单元格上创建 channelTitle
变量,而不是全局变量。另外,在prepareForReuse
上清除它以及您的其他单元格变量
我在这里可能弄错了,但是您是否在创建单元格后将channelTitle
设置在单元格上?正如我所看到的,在您的 viewController 中,您根据标题创建单元格,并且对于每个单元格,您将 TableViewController
的 channelTitle
设置为给定部分的标题。
如果是这种情况,那么在您调用 reloadData()
之前,TableViewCell
实际上并没有收到任何关于它应该加载什么的信息。
一般来说,我还建议在您的HomeVTwoTableViewCellSmall
中实现prepareForReuse
,因为它可以让您有机会清理任何过时的数据。您可能希望在该方法中设置cellChannel
和channelId
为空字符串或nil
,因此当重复使用单元格时,旧数据会保留。
另外,我刚刚重读了您拥有的单元格代码,看起来您正在layoutSubviews
中进行一些关键的初始单元格设置。该方法可能会被调用很多次,但您实际上只需要调用一次(对于它的大部分功能)。试试这个:
self.collectionView.dataSource = self
和self.collectionView.delegate = self
在channelTitle
上添加didSet
在视图控制器中设置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()
这样,您只会在单元格使用新频道更新时重新加载数据,而不是单元格视图的每个布局。
抱歉……又多了一个。我不知道您的channelTitle
实际上是如何通过的。正如我所看到的,您将 channelTitle 用作全局变量而不是本地变量。不要那样做!在实现上面的代码之前从当前位置删除channelTitle
。您会看到一些错误,因为您在 ViewController 中设置它并在单元格中访问它。您想要的是在 ViewController 的单元格上设置 channelTitle
(如上所述)。这也解释了为什么您在所有三个单元格中看到相同的数据。基本上,您只设置了一个 channelTitle
,并且所有三个单元格都在寻找该全局值来获取它们的数据。
希望能有所帮助!
(另外,您应该能够在 cellForRowAtIndexPath
方法中删除您的 else if
块,因为它后面的 else
块包含相同的代码。您也可以删除您的 viewDidLoad,因为它不是做任何事情,通常你应该看看你是否可以摆脱任何!
,因为它们不安全。改用?
或guard
或if let
)
【讨论】:
非常感谢您的帮助。我实施了您的更改,效果很好(没有重复),也感谢纠正我的不良编码习惯(我还在学习)。但现在的问题是,只有在我垂直滚动一点时才会加载数据。您认为我在某处缺少 reloadData() 吗?或者是什么导致了这个加载问题。 听起来问题可能是您第一次加载单元格时没有任何可用数据。您调用fetchDataLive
和fetchDataCommunity
之后,您可能会根据标题加载带有单元格的tableView 之后不久。但是,如果该 tableView 正在立即加载,那么很可能没有可用于填充这些单元格的数据(当您滚动时,数据可能可用)。看看有没有办法让 ViewController 知道这些 fetch 方法何时完成,然后在那里的桌子上调用reloadData
。
你说得对,我的 DataController().fetchDataLive(mode: "get")
和 DataController().fetchDataCommunity(mode: "get")
有问题。现在我将获取更改为仅更新(而不是删除和重写),它现在可以正常工作了。非常感谢。以上是关于TableView 中的 CollectionView 显示 false Data swift的主要内容,如果未能解决你的问题,请参考以下文章
使用 UICollectionViewDiffableDataSource 时如何重新加载 UICollectionView 中的部分数据?
获取 UITableViewCell 索引以响应位于 tableview 中的 tableview 中的按钮单击的正确方法?
TableView 未从另一个 tableview 中的 didselectRowAtindexPath 加载