2016-11-16 10 views
2

firebase-databaseからデータをロードするアプリケーションを構築しようとしています。UITableviewはFirebaseからデータをロードして行を複製します

Firebaseへのメンバーの保存は問題なく動作しています。 Firebaseのメンバーを私のUITableViewにロードすると、メンバーをソートしていて、最初の文字(AOS、B、Cなど、iOSの連絡先アプリケーションに見られるような)に従ってセクションヘッダの下にそれぞれメンバーを追加します。 問題がすべてのユーザーを読み込んだ後に表示されます。たとえば、タブ1に移動して[メンバー]タブに戻ると、表示されているすべてのメンバー/セルが複製されます。同じ手順を繰り返してタブを前後に切り替えると、すべてのセルが3重になり、それが続きます。

解決策のさまざまなソースを検索しましたが、類似するものは見つかりません。

誰かが解決策を知っているのですか、あるいは私が間違っていることはありますか?

ありがとうございます!

私の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()が1回だけ実行されます。アプリケーションを実行しているときに新しいテーブルを追加すると、tableViewは新しいデータで更新されたり、テーブルビューでユーザーを並べ替えたりしません。新しいユーザーを追加した後にtableView.reloadData()を実行しただけでも、createFirstnameDict()を使用せずにテーブルビューに追加されないため、この関数内で何か間違ったことをしたと思います。 – whoswho

+0

次に、メソッドをviewDidAppearに保持しますが、データを読み込む前に、配列と辞書を空にしてください。 – torinpitchers

0

あなたのcell.textlabelmembersDictからのデータを表示しています。 ビュー(タブを切り替えたとき)が読み込まれるたびに、loadDataFromFirebase()が呼び出されます。ここで

、すべての値が再びロードされますと、あなたはその後、membersDictに格納あなたのmembersValuesに追加されます。あなたはのviewDidLoad()の内部でそれらを宣言していないので

membersDictの新しいインスタンスが作成されません。クラス内で宣言していますが、関数の外に宣言しています。

追加するのは、配列の最後に要素を追加することです。要素を上書きしません。したがって、2つの名前を持つ配列がある場合は、名前を追加するとその名前が3番目の名前になり、既存の名前は上書きされません。

ビューをロードするたびに、すでに名前で構成されている配列に名前を追加します。これが複製の原因となっています。

は、あなたが複製されているかどうかを確認するために、あなたのmembersDictまたはmembersValuesの値を印刷してみてください。

membersDictのインスタンスをローカルに宣言することで、空の変数が毎回作成され、データを表示するようにローカルでこれを解決できます。

これが役に立ちます。

0

私の理解と経験から、あなたはそれに戻ったときに、あなたのオブザーバーはまだあなたがない限り聞いているので、他のビューコントローラから新たに作成したデータは、あなたのテーブルに表示されます

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

にfirebaseデータをロード他の視点に移動するときに聞くのをやめるように指示しています。

したがって、Firebaseに新しいデータが表示されると、テーブルに自動的に表示されます。

関連する問題