2016-11-16 56 views
2

我想構建一個從firebase-database加載數據的應用程序。UITableview從Firebase加載數據並複製行

將會員保存到Firebase的工作沒有任何問題。從Firebase加載成員到我的UITableView正在工作,然後我按照名字的第一個字母(A,B,C等在iOS聯繫應用程序中看到的)在分組標題下分別添加成員,並且這也工作正常我加載了所有用戶後出現問題,例如轉到Tab 1,然後切換回Members Tab,所有顯示的成員/單元格都被複制。如果我重複相同的步驟來回切換標籤所有細胞三重複,並繼續。

我已經搜索不同來源的解決方案,但我找不到任何相似的東西。

有誰知道解決方案或我做錯了什麼?

謝謝!

我的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前後:

TableView before and after

+0

您是否刪除或分離了EventListner?如果沒有,刪除它不會得到重複 –

+0

@Muhammad Farrukh Faizy我不確定你的意思? – whoswho

回答

0

我推薦你,是你清除你在你的事件監聽器上填充的所有數組。這樣你就可以確保當它從另一個視圖返回時它不會有舊的數據。事情是這樣的:

self.members.removeAll() 
+0

這工作,很容易申請。謝謝! – whoswho

1

問題是從你的方法來加載數據,是在錯誤的viewDidAppear安置產生的:

loadDataFromFirebase() 
createFirstnameDict() 

這意味着,每一次你的觀點似乎你的數據被一次又一次地加載。要解決這個問題,請將這些方法移到viewDidLoad中,並且您不會得到重複問題。所以你現在應該有:

override func viewDidLoad() { 
    super.viewDidLoad() 

    loadDataFromFirebase() 
    createFirstnameDict() 
} 

override func viewDidAppear(_ animated: Bool) { 
    super.viewDidAppear(animated) 

} 
+0

我可能會錯過某些東西,但您的答案似乎不是解決我的問題的方法。如果我這樣做,你建議數據和createFirstnameDict()將只運行一次。當我在應用程序運行時添加新的時,tableView將不會使用新數據進行更新,也不會在我的表視圖中對用戶進行排序。即使我在添加新用戶後只運行tableView.reloadData()本身,它也不會在沒有createFirstnameDict()的情況下添加到我的表視圖中,所以我相信我在這個函數中做了一些錯誤是否有意義? – whoswho

+0

然後保持您的方法在viewDidAppear中,但在您加載數據之前清空數組和字典。 – torinpitchers

0

您從cell.textlabel顯示數據membersDict。 每次你的視圖(當你切換標籤)加載時,它會調用loadDataFromFirebase()

在這裏,所有的價值再次得到裝載並獲得附加到membersValues你再membersDict存儲。

membersDict的新實例將不會產生因爲你沒有宣佈他們的裏面viewDidLoad中()。你已經在課堂內聲明瞭它們,但是在任何函數之外。

附加操作是在數組的末尾添加一個元素。它不覆蓋元素。所以,如果你有一個有兩個名字的數組,追加一個名字將使你的第三個名字不會覆蓋任何現有的名字。

每次加載視圖時,都會將名稱附加到已由名稱組成的數組上。這是造成重複的原因。

嘗試打印您的membersDictmembersValues,價值,以檢查是否正在複製。

您可以通過在本地聲明membersDict的實例來解決此問題,以便每次都創建一個空變量並使用它來顯示數據。

希望這會有所幫助。

0

從我的理解和經驗,你在

override func viewDidLoad() { 
    super.viewDidLoad() 
    loadFirebaseData() 
    } 

從任何其他視圖控制器新建的數據加載火力點數據,當您返回到它,因爲你的觀察家們還在聽,除非你將出現在您的表已告訴他們在轉移到其他觀點時停止聆聽。

因此,無論何時何時在Firebase中出現新數據,您的表格都會自動顯示它。

相關問題