我正在尝试构建一个从firebase-database加载数据的应用程序。
将成员保存到Firebase工作没有任何问题。从Firebase加载成员到我的UITableView
正在工作然后我正在对成员进行排序,并根据名字首字母(在iOS联系人应用程序中看到的A,B,C等)分别添加成员标题下的成员,这是我加载了所有用户之后发生了问题,例如转到标签1,然后切换回“成员”标签,所有显示的成员/单元格都重复。如果我重复相同的程序来回切换标签,所有单元格都会重复,然后继续。
我搜索了不同来源的解决方案,但我找不到任何相似的内容。
有谁知道解决方案或我做错了什么?
谢谢!
我的Viewcontroller:
import Foundation
import UIKit
class MembersTableViewController: UITableViewController {
var FBref = FIRDatabaseReference()
var members: [Member] = []
var membersDict = [String: [String]]()
var memberSectionTitles = [String]()
// TODO: Implement user.
//var user: AdminUser!
let fakeuservariable = "fakeuser"
@IBOutlet var memberListTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
loadDataFromFirebase()
createFirstnameDict()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return memberSectionTitles.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let firstLetterKey = memberSectionTitles[section]
if let firstnameValues = membersDict[firstLetterKey] {
return firstnameValues.count
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return memberSectionTitles[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "membercell", for: indexPath)
let firstLetterKey = memberSectionTitles[indexPath.section]
if let firstnameValues = membersDict[firstLetterKey] {
cell.textLabel?.text = firstnameValues[indexPath.row]
// Not working
//let memberDetails = members[indexPath.row]
//cell.detailTextLabel!.text = "Amount left: \(memberDetails.memberamount)"
}
return cell
}
func createFirstnameDict() {
for firstname in members {
var firstLetter = firstname.firstname
let firstnameKey = firstLetter.substring(to: firstLetter.characters.index(firstLetter.startIndex, offsetBy: 1))
if var memberValues = membersDict[firstnameKey] {
memberValues.append(firstLetter)
membersDict[firstnameKey] = memberValues
} else {
membersDict[firstnameKey] = [firstLetter]
}
}
memberSectionTitles = [String](membersDict.keys)
memberSectionTitles = memberSectionTitles.sorted { $0 < $1 }
}
func loadDataFromFirebase() {
let FBref = FIRDatabase.database().reference()
FBref.child("member-list").observeSingleEvent(of: .value, with: { (snapshot) in
var resultItem: [Member] = []
for item in snapshot.children {
let memberItem = Member(snapshot: item as! FIRDataSnapshot)
resultItem.append(memberItem)
}
self.members = resultItem
self.createFirstnameDict()
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
}
我的会员模特:
import Foundation
struct Member {
let firstname: String
let lastname: String
let email: String
let phonenumber: String
let socialsecuritynr: String
let memberamount: String
let addedByUser: String
let key: String
let ref: FIRDatabaseReference?
init(firstname: String, lastname: String, email: String, phonenumber: String, socialsecuritynr: String, memberamount: String, addedByUser: String, key: String = "") {
self.key = key
self.firstname = firstname
self.lastname = lastname
self.email = email
self.phonenumber = phonenumber
self.socialsecuritynr = socialsecuritynr
self.memberamount = memberamount
self.addedByUser = addedByUser
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
firstname = snapshotValue["firstname"] as! String
lastname = snapshotValue["lastname"] as! String
email = snapshotValue["email"] as! String
phonenumber = snapshotValue["phonenumber"] as! String
socialsecuritynr = snapshotValue["socialsecuritynr"] as! String
memberamount = snapshotValue["memberamount"] as! String
addedByUser = snapshotValue["addedByUser"] as! String
ref = snapshot.ref
}
func toAnyObject() -> Any {
return ["firstname": firstname, "lastname": lastname, "email": email, "phonenumber": phonenumber, "socialsecuritynr": socialsecuritynr, "memberamount":memberamount, "addedByUser": addedByUser]
}
}
这是我之前和之后的TableView:
答案 0 :(得分:1)
问题来自于放置加载viewDidAppear中错误数据的方法:
loadDataFromFirebase()
createFirstnameDict()
这意味着每次您的视图出现时,您的数据都会反复加载。要解决此问题,请将这些方法移到viewDidLoad中,您不会遇到重复问题。所以你现在应该:
override func viewDidLoad() {
super.viewDidLoad()
loadDataFromFirebase()
createFirstnameDict()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
答案 1 :(得分:0)
我建议你清除你在事件监听器之前填充的所有数组。这样,您可以确保当它从另一个视图返回时,它将不会有旧数据。像这样:
self.members.removeAll()
答案 2 :(得分:0)
您正在 cell.textlabel 中显示来自 membersDict 的数据。 每当您的视图(切换标签时)加载时,它都会调用 loadDataFromFirebase()。
此处,所有值都会再次加载并附加到 membersValues ,然后存储在 membersDict 中。
由于您未在 viewDidLoad()中声明它们,因此无法创建 membersDict 的新实例。你已经在类中声明了它们,但在任何函数之外。
追加的内容是在数组的末尾添加一个元素。它不会覆盖元素。因此,如果您有一个包含两个名称的数组,附加一个名称将使其成为您的第三个名称,而不会覆盖任何现有名称。
每次加载视图时,都会将名称附加到已包含名称的数组中。这就是造成重复的原因。
尝试打印 membersDict 或 membersValues 的值,以检查是否重复。
您可以通过在本地声明 membersDict 的实例来解决此问题,以便每次都创建一个空变量并使用它来显示数据。
希望这会有所帮助。
答案 3 :(得分:0)
根据我的理解和经验,您可以在
中加载firebase数据 override func viewDidLoad() {
super.viewDidLoad()
loadFirebaseData()
}
当您返回到桌面时,来自任何其他视图控制器的新创建的数据将显示在您的桌面上,因为除非您在移动到其他视图时告诉他们停止收听,否则您的观察者仍在监听。
因此,只要Firebase中出现新数据,您的表格就会自动显示。