私は2つのタブを持つtabBarコントローラを持っています:tabAはClassAを含み、tabBはClassBを含みます。私はtabA/ClassAのFirebaseデータベースにデータを送信し、TabB/ClassBのデータベースを調べて、それを取得してtableViewに追加します。 tableViewのセルの中には、現在データベース内にあるスニーカーの数が表示されます。スウィフトiOS - Firebase Observerの外でテーブルビューを再ロードする方法.child追加して重複値を除外しますか?
私は.observeSingleEvent(.value)
と.observe(.childAdded)
の違いを知っています。 TabAにデータが送信されている間にtabBに切り替えると、tabA/ClassAが完了したら新しいデータがtableViewに追加されたことを確認したいので、ライブアップデートが必要です。
私はviewWillAppearに私のオブザーバーを持っています。私はそれをpullDataFromFirebase()
の関数の中に置き、ビューが現れるたびに関数が実行されます。また、TabViewを更新するように、tabA/ClassAで送信されるデータをリッスンする通知オブザーバもあります。通知イベントはpullDataFromFirebase()
を再度実行します
ClassAでは、FireBasicの呼び出しのコールバック内に、ClassBのpullDataFromFirebase()
関数を実行する通知ポストがあります。
私が実行している問題は、新しいデータが更新されている間にタブBに入っているときです。完了すると、データを表示するセルにカウントがあり、カウントがスローされます。私はそれをデバッグし、データを保持するsneakerModels配列は時々複製され、新しく追加されたデータを3倍にします。例えば
私はクラスBで午前とスニーカーの2組がデータベースに存在する場合、pullDataFromFirebase()
funcが実行され、のtableViewセルが起こっていた何
「あなたはスニーカーの2ペアを持っている」と表示されます私はtabA/ClassAに切り替えて、スニーカー1ペアを追加しましたが、TabB/ClassBに切り替えると、セルはまだ "あなたは2ペアのスニーカーを持っています"と言いますが、セルを更新すると "You 5組のスニーカーを持っていて、5つの細胞が出現するでしょうか?タブを切り替えて戻ってきたら、「あなたは3ペアのスニーカーがあります」と正しい量のセルが正しく表示されます。
通知が届いた場所です。同じプロセスを経て2つのスニーカーで始めると、「あなたは2ペアのスニーカーがあります」と表示され、別のペアを追加してスイッチを追加しますtabBに戻り、「あなたは2ペアのスニーカーを持っています」と表示されます。データが送信されると、セルには「あなたに5ペアのスニーカーがあります」と表示され、5セルが表示されます。「スニーカーが3ペアあります」と正しいセル量に正しく更新されます(スイッチタブ)。
通知は機能していたようですが、その短い間違った瞬間がありました。
セマフォを使用する必要があると主張したが、セマフォが非同期的に使用されることを意図していないと答えたいくつかの投稿がありました。 セマフォの参照を除外するために私の質問を更新しなければならなかった。
今私は、pullDataFromFirebase()の完了ハンドラでtableView.reloadData()を実行しています。
重複した値を防ぐために終了したら、オブザーバーの外にtableViewを再ロードするにはどうすればよいですか?
モデル:
class SneakerModel{
var sneakerName:String?
}
TABB/ClassBの:
ClassB: UIViewController, UITableViewDataSource, UITableViewDelegate{
var sneakerModels[SneakerModel]
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(pullDataFromFirebase), name: NSNotification.Name(rawValue: "pullFirebaseData"), object: nil)
}
override func viewWillAppear(_ animated: Bool){
super.viewWillAppear(animated)
pullDataFromFirebase()
}
func pullDataFromFirebase(){
sneakerRef?.observe(.childAdded, with: {
(snapshot) in
if let dict = snapshot.value as? [String:Any]{
let sneakerName = dict["sneakerName"] as? String
let sneakerModel = SneakerModel()
sneakerModel.sneakerName = sneakerName
self.sneakerModels.append(sneakerModel)
//firebase runs on main queue
self.tableView.reloadData()
}
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sneakerModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SneakerCell", for: indexPath) as! SneakerCell
let name = sneakerModels[indePath.row]
//I do something else with the sneakerName and how pairs of each I have
cell.sneakerCount = "You have \(sneakerModels.count) pairs of sneakers"
return cell
}
}
}
タバ/にClassA:私のアプリの他の部分で
ClassA : UIViewController{
@IBAction fileprivate func postTapped(_ sender: UIButton) {
dict = [String:Any]()
dict.updateValue("Adidas", forKey: "sneakerName")
sneakerRef.?.updateChildValues(dict, withCompletionBlock: {
(error, ref) in
//1. show alert everything was successful
//2. post notification to ClassB to update tableView
NotificationCenter.default.post(name: Notification.Name(rawValue: "pullFirebaseData"), object: nil)
}
}
}
基本的に、非同期データ処理を回避するためにセマフォを使用しないでください。通知を送信し、通知の受信者に非同期コード( 'updateChildValues')を実行することはオプションか?または、追加されたオブジェクトを通知に渡し、データを再取得せずにデータソース配列を更新します。 – vadian
@vadianは助けてくれてありがとう。私がやっていることじゃない?ポストはClassAで送信され、受信者はClassBです。 updateChildValuesは、ClassBにあるpullFirebaseData関数で実行されるものです。なぜ非同期プロセスにセマフォを使用しないのですか? –
非同期に処理する正しい方法があります。セマフォはそうではありません。 – matt