从 Firebase 将一组对填充到 tableView 中以仅显示前 3 个最高分数
Posted
技术标签:
【中文标题】从 Firebase 将一组对填充到 tableView 中以仅显示前 3 个最高分数【英文标题】:Populating an array of pairs into a tableView from Firebase to display only the top 3 highest scores 【发布时间】:2018-12-04 01:31:11 【问题描述】:我正在尝试用一组对(一个 Int,一个 String)填充我的 tableView。不幸的是,我无法理解为什么它不起作用,因为我似乎无法填充 tableView,我收到 indexOutOfRange 作为错误。我使用 firebase 作为我的数据库来检索我想要填充的数据。请看下文....
class Leaderboard: UIViewController, UITableViewDataSource, UITableViewDelegate
private let padding = 12
private var quiz: Quiz!
private let backgroundImageView = UIImageView()
private let contentView = UIView()
private let leaderboardLabel = UILabel()
private let rankLabel = UILabel()
private let userLabel = UILabel()
private let scoreLabel = UILabel()
private let tableViewCellHeight: CGFloat = 60
private let bottomButton = BottomBorderedButtons()
var scoresArray = [ScoreClass]()
var topScoresTableView: UITableView =
let tableView = UITableView()
return tableView
()
override func viewDidLoad()
super.viewDidLoad()
retrieveUserData()
setupViews()
required init(quiz: Quiz)
super.init(nibName: nil, bundle: nil)
defer
self.quiz = quiz
required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")
class ScoreClass
var name = ""
var score = 0
init(withName: String, andScore: Int)
name = withName
score = andScore
let ref = Database.database().reference()
func retrieveUserData()
let postsRef = self.ref.child("Users")
let query = postsRef.queryOrdered(byChild: "highscore").queryLimited(toLast: 3)
query.observeSingleEvent(of: .value, with: snapshot in
for child in snapshot.children
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let name = dict["username"] as! String
let score = dict["highScore"] as! Int
let aScore = ScoreClass(withName: name, andScore: score)
self.scoresArray.insert(aScore, at: 0)
for s in self.scoresArray
print(s.score, s.name)
)
self.topScoresTableView.reloadData()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
var countarr = 0
for s in self.scoresArray
countarr = s.name.count
print(s.score, s.name)
print(countarr)
return countarr
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = topScoresTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let scoreClassObject = scoresArray[indexPath.row]
let name = scoreClassObject.name
let score = scoreClassObject.score
cell.backgroundColor = UIColor.clear
cell.usernameLabel.text = name
cell.resultLabel.text = String(score)
cell.rankNumberLabel.text = "\(indexPath.row + 1)"
print(scoresArray)
return cell
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
return 44
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
return 10.0
func setupViews()
view.addSubview(backgroundImageView)
backgroundImageView.addSubview(contentView)
contentView.addSubview(leaderboardLabel)
contentView.addSubview(rankLabel)
contentView.addSubview(userLabel)
contentView.addSubview(scoreLabel)
contentView.addSubview(topScoresTableView)
contentView.addSubview(bottomButton)
self.backgroundImageView.snp.makeConstraints (make) in
make.top.equalTo(topLayoutGuide.snp.bottom)
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.bottom.equalToSuperview()
self.backgroundImageView.contentMode = UIViewContentMode.scaleAspectFill
self.backgroundImageView.isUserInteractionEnabled = true
self.backgroundImageView.image = UIImage(named: "Stars.png")
self.contentView.snp.makeConstraints (make) in
make.edges.equalToSuperview()
contentView.backgroundColor = transluscentGrey
self.leaderboardLabel.snp.makeConstraints (make) in
make.top.equalToSuperview()
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.bottom.equalTo(topScoresTableView.snp.top).offset(-50)
make.centerX.equalToSuperview()
leaderboardLabel.textAlignment = .center
leaderboardLabel.numberOfLines = 0
leaderboardLabel.textColor = .white
leaderboardLabel.font = UIFont.boldSystemFont(ofSize: 28.0)
leaderboardLabel.text = "Leaderboard"
leaderboardLabel.backgroundColor = tableViewCell
self.rankLabel.snp.makeConstraints (make) in
make.top.equalTo(leaderboardLabel.snp.bottom).offset(10)
make.leading.equalToSuperview().offset(padding)
make.height.equalTo(30)
rankLabel.textAlignment = .center
rankLabel.numberOfLines = 0
rankLabel.baselineAdjustment = .alignCenters
rankLabel.textColor = .white
rankLabel.font = UIFont(name: "SFUIDisplay-Medium", size: 3)
rankLabel.layer.cornerRadius = 5.0
rankLabel.clipsToBounds = true
rankLabel.text = "Rank"
self.userLabel.snp.makeConstraints (make) in
make.top.equalTo(leaderboardLabel.snp.bottom).offset(10)
make.leading.equalTo(rankLabel.snp.trailing).offset(padding)
make.height.equalTo(30)
make.width.equalToSuperview().multipliedBy(0.50)
userLabel.textAlignment = .center
userLabel.numberOfLines = 0
userLabel.baselineAdjustment = .alignCenters
userLabel.textColor = .white
userLabel.font = UIFont(name: "SFUIDisplay-Medium", size: 3)
userLabel.layer.cornerRadius = 5.0
userLabel.clipsToBounds = true
userLabel.text = "Username"
self.scoreLabel.snp.makeConstraints (make) in
make.top.equalTo(leaderboardLabel.snp.bottom).offset(10)
make.leading.equalTo(userLabel.snp.trailing).offset(padding)
make.height.equalTo(30)
make.trailing.equalToSuperview().offset(-padding)
scoreLabel.textAlignment = .center
scoreLabel.numberOfLines = 0
scoreLabel.baselineAdjustment = .alignCenters
scoreLabel.textColor = .white
scoreLabel.font = UIFont(name: "SFUIDisplay-Medium", size: 3)
scoreLabel.layer.cornerRadius = 5.0
scoreLabel.clipsToBounds = true
scoreLabel.text = "Score"
self.topScoresTableView.snp.makeConstraints (make) in
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.height.equalToSuperview().multipliedBy(0.65)
make.bottom.equalToSuperview().offset(-30)
topScoresTableView.delegate = self
topScoresTableView.register(TableViewCell.self, forCellReuseIdentifier: "cell")
topScoresTableView.dataSource = self
topScoresTableView.backgroundColor = UIColor.clear
self.bottomButton.snp.makeConstraints (make) in
make.top.lessThanOrEqualTo(topScoresTableView.snp.bottom).offset(5)
make.width.equalTo(60)
make.bottom.equalToSuperview().offset(-5)
make.centerX.equalToSuperview()
self.bottomButton.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
self.bottomButton.backgroundColor = .yellow
【问题讨论】:
检查您的 numberOfRowsInSection 函数。您返回的计数错误。 即使我修改计数以返回 self.scoresArray.count。 func tableView cellForRowAt 没有被调用 self.topScoresTableView.reloadData() 放错地方了。 Firebase 是异步的,这将在闭包中读取数据之前被调用。您需要在闭包中调用 tableView.reloadData() 以便在读入数据后执行它。就在 self.scoresArray 循环中的 for 之后。 【参考方案1】:让我们把它分解成它的部分
从 Firebase 填充并保存名称和分数的 ScoreClass 对象
class ScoreClass
var name = ""
var score = 0
init(withName: String, andScore: Int)
name = withName
score = andScore
存放 ScoreClass 对象的数组,用作 tableView 的数据源
var scoresArray = [ScoreClass]()
读取 Firebase 并填充数组的代码
func getScoresAndNamesFromFirebaseAndStuffIntoArray()
let postsRef = self.ref.child("Users")
let query = postsRef.queryOrdered(byChild: "highscore").queryLimited(toLast: 3)
query.observeSingleEvent(of: .value, with: snapshot in
for child in snapshot.children
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let name = dict["username"] as! String
let score = dict["highScore"] as! Int
let aScore = ScoreClass(withName: name, andScore: score)
self.scoresArray.insert(aScore, at: 0)
self.topScoresTableView.reloadData()
)
然后是 tableView 委托方法。有三个函数来处理 tableView。这假设您在 tableView 中的文本单元格的标识符为 NameScoreCell
let textCellIdentifier = "NameScoreCell"
func numberOfSections(in tableView: UITableView) -> Int
return 1
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return scoresArray.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: textCellIdentifier, for: indexPath as IndexPath)
let row = indexPath.row
let scoreObject = scoresArray[row]
let score = scoreObject.score
let name = scoreObject.name
cell.nameLabel?.text = name
cell.scoreLabel?.text = score
return cell
【讨论】:
【参考方案2】:替换这个函数:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return self.scoresArray.count
【讨论】:
但是当我这样做时, func tableView cellForRowAt 根本不会被调用。所以 tableView 中什么都没有显示。 setupViews() 在哪里? tableView 在哪里添加到视图中? tableView 委托和数据源设置在哪里?我认为缺少一些步骤。 很抱歉没有把它们放进去,因为我认为它会有点太长了。我已将它们添加到问题中。 好的。杰伊的回答是什么时候调用 reloadData() 结合这个应该看到你是对的。以上是关于从 Firebase 将一组对填充到 tableView 中以仅显示前 3 个最高分数的主要内容,如果未能解决你的问题,请参考以下文章
jQuery/Javascript:如何获得一组对中的第 n 对?
如何将一组地图从 Firestore 映射到 recyclerView?