我正在尝试创建一个聊天应用程序,但是发生在我身上的问题是我试图在表格视图中获取单元格以显示用户的显示名称。但是出于某种原因,它总是说零。这使我相信我的结构或引用数据的方式有问题。
结构
struct User {
let name: String!
let uid: String!
}
表格视图单元格
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
// **** Crash is on the following line ****
let nameTxtField = cell.viewWithTag(1) as! UILabel
nameTxtField.text = users[indexPath.row].name
return cell
}
表格视图viewDidload
override func viewDidLoad() {
super.viewDidLoad()
let uid = Auth.auth().currentUser?.uid
let ref: DatabaseReference! = Database.database().reference()
ref.child("users").child(uid!).queryOrderedByKey().observe(.childAdded) { (snapshot) in
let name = (snapshot.value as? NSDictionary)?["name"] as? String ?? ""
let uid = (snapshot.value as? NSDictionary)?["uid"] as? String ?? ""
self.users.append(User(name: name, uid: uid))
self.tableView.reloadData()
}
tableView.reloadData()
}
答案 0 :(得分:1)
queryOrderedBy...
和.childAdded
仅在您希望基于某种条件从列表中获取多个子代时才需要。但是在您的情况下,您知道子节点的确切路径,因此您不需要查询。
因此,您正在执行直接读取,但是正在使用queryOrderedByKey()
和.childAdded
。这意味着您的闭包将在/users/rPJSO...
下的每个子级中被调用,对于每个单独的属性分别被调用一次:email
,name
,password
,uid
。而且,由于其中没有任何一个属性{strong},因此该查找将返回name
。
解决方案非常简单:删除nil
并收听queryOrderedByKey
:
.value
其余代码可以保持不变。
答案 1 :(得分:1)
根据您的评论,您可能会遇到崩溃
let nameTxtField = cell.viewWithTag(1) as! UILabel
这意味着viewWithTag(1)
返回nil
或UILabel
以外的内容。您可能尚未将标签的标签设置为1,或者您有多个带有标签1的UI元素(viewWithTag
将返回带有该标签的层次结构中的第一个视图)。
您应该创建一个适当的UITableViewCell
子类,并将您的UILabel
链接到该类的属性。然后您可以说:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyTableViewCell
cell.nameTxtField.text = users[indexPath.row].name
其他一些评论;您应该尝试消除尽可能多的信息!尽可能。
struct User {
let name: String
let uid: String
}
uid
语句检索guard
,而不是在以后强行打开包装NS...
对象
override func viewDidLoad() {
super.viewDidLoad()
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let ref: DatabaseReference! = Database.database().reference()
ref.child("users").child(uid).queryOrderedByKey().observe(.childAdded) { (snapshot) in
guard let result = snapshot.value as? [String:Any] else {
return
}
let name = (result["name"] as? String) ?? ""
let uid = (result["uid"] as? String) ?? ""
self.users.append(User(name: name, uid: uid))
self.tableView.reloadData()
}
}
答案 2 :(得分:1)
问题似乎在此行中:
let nameTxtField = cell.viewWithTag(1) as! UILabel
该单元尚未从情节提要中加载,因此cell.viewWithTag(1)
为零。零+! =崩溃。
通常,我使用以下算法填充单元格:
customizeUI()
,以填充单元格上必要的UI控件添加要在此单元格中显示的数据类型的iVar,并在其设置方法中调用customUI()。
var item:HistoryItem? { didSet { customUI() } }
此方法检查单元是否已加载:
func customizeUI() {
guard let label = self.nameLabel else {
return
}
// Fill UI controlls
label.text = item.name
...
}
还必须在单元格awakeFromNib()
方法中调用此方法。
最后,在您的cellAt...
方法中,您必须编写类似cell.item = dataItem
的内容,而不是直接填充UI控件。