如何在每个表格视图单元格中加载不同的数据
我有一个包含聊天室列表的表格视图,并且我试图获取每个单元格中所有成员头像的集合视图。如何在每个表格视图单元格中加载不同的数据
当我有它,我的函数获取有关的室成员所需的信息,并将其设置字典中cellForRow
:
DispatchQueue.main.async {
self.getParticipantInfo(roomId: self.usersRooms[(indexPath as NSIndexPath).row].id)
existingRoomCell.avatarView.addSubview((self.navCollectionView?.view)!)
}
这是从火力地堡获取数据的功能:
var avatarDictionary = NSMutableDictionary()
var statusDictionary = NSMutableDictionary()
func getParticipantInfo(roomId: String) {
let databaseRef = FIRDatabase.database().reference()
let groupRef = databaseRef.child("groups").child(roomId)
groupRef.observe(.childAdded, with: { snapshot in
if let snapDict = snapshot.value as? [String : AnyObject] {
for each in snapDict {
let uid = each.key
let avatar = each.value["profilePicture"] as! String
let status = each.value["status"] as! String
// Set those to the dictionaries [UID : value]
self.avatarDictionary.setValue(avatar, forKey: uid)
self.statusDictionary.setValue(status, forKey: uid)
DispatchQueue.main.async {
self.navCollectionView?.collectionView?.reloadData()
print("\n\nDone\n\n")
}
}
print("\n\navatarDictionary:\n \(self.avatarDictionary)")
print("\nstatusDictionary:\n \(self.statusDictionary)")
}
})
}
我看到打印到控制台的每本字典中有5个(我目前有5个房间),所以它看起来像是为每个房间分开的字典。然而,我坚持如何指定哪些字典用于哪个房间,因此只有该房间的成员出现在相应的表格视图单元格中。
在集合视图的例如cellForItem
方法,我通过获取来自avatarDictionary所有值到一个数组设置头像:
DispatchQueue.main.async {
let avatars = self.roomVC?.avatarDictionary.allValues as! [String]
navBarCell.avatarImageView.loadImageUsingCacheWithUrlString(avatars[indexPath.row])
}
但是因为我有多个词典现在,我不知道如何指定哪些字典是表格中的哪个房间。目前它只使用一个(我认为第一个)avatarDictionary
,所以化身只显示在表中的一个房间。
我该如何解决这个问题,让集合视图从正确的字典中加载头像,而不仅仅是一个?
由于Firebase调用是异步的,因此我建议将roomId
传递给您的tableviewcell并让单元格处理加载头像和状态。
例如,一些伪代码:
class CustomCell: UITableViewCell {
var roomId:String? {
didSet {
if let roomId = roomId {
getParticipantInfo(roomId)
} else {
//clear the data and cancel any pending Firebase request
}
}
}
func getParticipantInfo(roomId: String) {
//load your room, parse the data into your dictionaries and use the dictionary to power the collectionview datasource
collectionView.reloadData()
}
func prepareForReuse() {
super.prepareForReuse()
roomId = nil
}
}
编辑基于评论
快速的问题 - 你的问题中提到的TableView和变量的CollectionView。解决方案无关紧要,但它是哪一个?
我可以想象2种不同的方法来存储您的数据。您选择哪个取决于您的实际数据的外观。
如果每个房间的头像/身份都是唯一的,并且假设您只有一个部分,那么我们只需要关闭行。我会做一个结构来保存你的数据,使一切都变得更清晰。在这里,我有一个RowData结构数组,它包含roomId和一个Avatar结构数组,它们保存imageURL和状态。这样你就没有两个平行的数组或明确相关信息的字典。如果我错误地假设,请纠正我。您现在可以使用行作为索引访问头像数据。
struct Avatar {
var imageURL: String
var status: String //eventually this is better as an enum
}
struct RowData {
let roomId:String
var avatars = [Avatar]()
init(roomId: String) {
self.roomId = roomId
}
}
var rowData = [Int: RowData]()
func getParticipantInfo(roomId: String, row: Int) {
let databaseRef = FIRDatabase.database().reference()
let groupRef = databaseRef.child("groups").child(roomId)
var thisRow = RowData(roomId: roomId)
rowData[row] = thisRow
groupRef.observe(.childAdded, with: { snapshot in
if let snapDict = snapshot.value as? [String : AnyObject] {
for each in snapDict {
guard let imageURL = each.value["profilePicture"] as? String, let status = each.value["status"] as? String else { continue }
let avatar = Avatar(imageURL: imageURL, status: status)
thisRow.avatars.append(avatar)
}
DispatchQueue.main.async {
self.navCollectionView?.collectionView?.reloadItems(at:[IndexPath(section:0, row:row)])
print("\n\nDone\n\n")
}
}
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as RoomCell
if let thisRowData = rowData[indexPath] {
cell.rowData = rowData[indexPath.row]
} else {
getParticipantInfo(roomId: usersRooms[indexPath.row].id, row: indexPath.row)
}
}
class RoomCell: UITableViewCell, UICollectionViewDataSource {
var collectionView:UICollectionView
var rowData:RowData? {
didSet {
collectionView.reloadData()
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return rowData ? rowData?.avatars.count : 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(for: indexPath)
let avatar = rowData?.avatars[indexPath.row]
}
}
或者,如果有大量的不同行化身之间的重叠,你可以像var roomIds:[String]
增加一个道具头像结构,并有[Avatar]
一个数组,然后在roomId
过滤来填充行。这种模式的优点是,如果你的API返回多行的头像信息,你将有效地缓存跨多行数据,并没有重复的头像对象
集合视图类使用表视图控制器的字典作为数据源:https://pastebin.com/3ft1qS1W,我会使用自定义单元格作为数据源(即'let avatars = self.customCell?.avatarDictionary.allValues as![String]'而不是'let avatars = self.roomVC?.avatarDictionary.allValues as![String]') – KingTim
我可能不完全了解您的原始问题。我假设每个tableviewcell都显示一组独特的异步数据。你是否暗示情况并非如此?如果您将字典作为tableviewcontroller的一部分,那么在加载异步数据之后,您需要存储数据,然后将单元格重新加载到正确的索引路径。如果这是正确的假设,我也可以模拟一个样本。 – dmorrow
这是正确的,每个tableview单元格显示该房间成员的头像 - getParticipants函数传递一个roomID,它获得该房间成员的头像和状态,并将它们设置为字典。这是我迷路的地方 - 我不确定如何确保一旦设置了这些字典,程序将知道如何使用Dict A作为单元格A的数据源,将Dict B作为单元格B的数据源,等等上。随着你的答案,我不知道是否应该从表视图控制器中删除该功能和所有字母并将它们移动到单元格。 – KingTim