2016-09-27 5 views
2

Я прочитал другое переполнение стека q & a об этой проблеме, но это проблема с tabBarController, в которой я ничего не нашел.Firebase removeAllObservers() продолжает делать вызовы при переключении просмотров -Swift2 iOS

У меня есть tabBarController с 3 вкладками. tab1 - это место, где я успешно отправляю информацию в Firebase. В tab2 у меня есть tableView, который успешно считывает данные из tab1.

В tab2 мой слушатель находится в видуWillAppear. Я удаляю слушателя в viewDidDisappear (я также пробовал viewWillDisappear), и где-то здесь возникает проблема.

override func viewDidDisappear(animated: Bool) { 
    self.sneakersRef!.removeAllObservers() 
    //When I tried using a handle in viewWillAppear and then using the handle to remove the observer it didn't work here either 
    //sneakersRef!.removeObserverWithHandle(self.handle) 
    } 

После того, как я перейти с tab2 на любую другую вкладку, то второй я возвращаюсь к TAB2 двойники таблиц данных, а затем, если я снова переключить вкладки и вернуться утраивает и т.д. Я попытался установить слушатель внутри viewDidLoad который предотвращает дублирование данных таблицы при переключении вкладок, но когда я отправляю новую информацию из tab1, информация никогда не обновляется в tab2.

В соответствии с документами Firebase и почти всем остальным, что я читал в stackoverflow/google, слушатель должен быть установлен в viewWillAppear и удален в viewDidDisappear.

Любые идеи о том, как предотвратить дублирование данных при каждом переключении между вкладками?

tab1

import UIKit 
import Firebase 
import FirebaseAuth 
import FirebaseDatabase 

class TabOneController: UIViewController{ 

var ref:FIRDatabaseReference! 
@IBOutlet weak var sneakerNameTextField: UITextField! 

override func viewDidLoad() { 
     super.viewDidLoad() 
     self.ref = FIRDatabase.database().reference() 
} 

@IBAction func sendButton(sender: UIButton) { 

     let dict = ["sneakerName":self.sneakerNameTextField.text!] 

     let usersRef = self.ref.child("users") 
     let sneakersRef = usersRef.child("sneakers").childByAutoID() 

     sneakersRef?.updateChildValues(dict, withCompletionBlock: {(error, user) in 
       if error != nil{ 
        print("\n\(error?.localizedDescription)") 
       } 
      }) 
     } 
} 

tab2

import UIKit 
import Firebase 
import FirebaseAuth 
import FirebaseDatabase 

class TabTwoController: UITableViewController{ 

@IBOutlet weak var tableView: UITableView! 

var handle: Uint!//If you read the comments I tried using this but nahhh didn't help 
var ref: FIRDatabaseReference! 
var sneakersRef: FIRDatabaseReference? 
var sneakerArray = [String]() 

override func viewDidLoad() { 
     super.viewDidLoad() 
     self.ref = FIRDatabase.database().reference() 
    } 

override func viewWillAppear(animated: Bool) { 
     super.viewWillAppear(animated) 

     let usersRef = self.ref.child("users") 
     //Listener 
     self.sneakersRef = usersRef.child("sneakers") 

     //I tried using the handle 
     //---self.handle = self.sneakersRef!.observeEventType(.ChildAdded... 

     self.sneakersRef!.observeEventType(.ChildAdded, withBlock: {(snapshot) in 

     if let dict = snapshot.value as? [String:AnyObject]{ 

     let sneakerName = dict["sneakerName"] as? String 
     self.sneakerArray.append(sneakerName) 

     dispatch_async(dispatch_get_main_queue(), { 
       self.tableView.reloadData() 
     }) 

    } 

    }), withCancelBlock: nil) 
} 

//I also tried viewWillDisappear 
override func viewDidDisappear(animated: Bool) { 

     self.sneakersRef!.removeAllObservers() 

     //When I tried using the handle to remove the observer it didn't work either 
     //---sneakersRef!.removeObserverWithHandle(self.handle) 
    } 


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return self.sneakerArray.count 
    } 

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cell = self.tableView.dequeueReusableCellWithIdentifier("sneakerCell", forIndexPath: indexPath) 
     cell.textLabel?.text = sneakerArray[indexPath.row] 
     return cell 
    } 
} 

tab3 ничего не делает. Я просто использую его как альтернативную вкладку для переключения взад и вперед с помощью

ответ

2

Метод removeAllObservers работает правильно. Проблема, которую вы сейчас испытываете, вызвана незначительной недостающей деталью: вы никогда не очистить содержание sneakerArray.


Примечание: нет необходимости dispatch_async внутри обратного вызова события. Firebase SDK вызывает эту функцию в главной очереди.

+0

Спасибо за помощь. Я удалил содержимое массива в viewDidDisappear после метода removeAllObserver(), например: self.sneakersRef! .removeAllObservers(), а затем self.sneakerArray.removeAll(). Он прекратил копировать. На самом деле я был очень стеснен в этом. Можете ли вы объяснить, почему мне нужно очистить массив? Из моего понимания каждый раз, когда представление загружается снова, содержимое в массиве одинаково. –

+1

Когда вы начинаете подписку на узел Firebase, первое, что делает SDK, это загрузка текущего содержимого. С событиями '.childAdded' это означает, что вы получаете один обратный вызов для каждого ребенка; каждый раз, когда вы подписываетесь. Вы просто добавляете детей при каждом обратном вызове, что приводит к дублированию. – vzsg

0

Благодарим за задание этого вопроса.

У меня также был такой же вопрос в прошлом. Я решил эту проблему следующим образом.

1) Определить массив, содержащий список наблюдателей.

var aryObserver = Array<Firebase>() 

2) Добавить наблюдателя, как следует.

self.sneakersRef = usersRef.child("sneakers") 
aryObserver.append(self.sneakersRef) 

3) Снимите наблюдателя, как следует.

for fireBaseRef in self.aryObserver{ 
      fireBaseRef.removeAllObservers() 
     } 

self.aryObserver.removeAll() //Remove all object from array. 
+0

Это не сработало. Я попробовал это в viewDidDisappear –

+0

Поместите последний код в viewWillDisappear вместо viewDidDisappear bcoz его вызов первым. – iMHitesh

+0

Все еще не работает. Я попытался переместить код в нескольких разных местах. Nadaaaaa –

1

Официальный признанный Ответ был отправлен @vzsg. Я просто детализирую его для следующего человека, который сталкивается с этой проблемой. Проголосуйте за его ответ.

Что в основном происходит, когда вы используете .childAdded, Firebase перемещается вокруг и захватывает каждого ребенка из узла (in my case the node is "sneakersRef"). Firebase захватывает данные, добавляет их в массив (in my case self.sneakerArray), затем возвращается, чтобы получить следующий набор данных, добавляет его в массив и т. Д. Очищая массив в начале следующего цикла, массив будет пустым после выполнения FB. Если вы переключаете сцены, у вас всегда будет пустой массив, и единственные данные, которые отобразит ui, - это FB, который снова зацикливает узел.

Также я избавился от вызова dispatch_async, потому что он сказал, что FB вызывает функцию в основной очереди. Я использовал только self.tableView.reloadData()

На боковой ноте вы должны подписаться на firebase-community.slack.com. Это официальный канал Firebase Slack, и именно там я разместил этот вопрос и vzsg ответил на него.

override func viewWillAppear(animated: Bool) { 
     super.viewWillAppear(animated) 

    //CLEAR THE ARRAY DATA HERE before you make your Firebase query 
    self.sneakerArray.removeAll() 

    let usersRef = self.ref.child("users") 
    //Listener 
    self.sneakersRef = usersRef.child("sneakers") 

    //I tried using the handle 
    //---self.handle = self.sneakersRef!.observeEventType(.ChildAdded... 

    self.sneakersRef!.observeEventType(.ChildAdded, withBlock: {(snapshot) in 

    if let dict = snapshot.value as? [String:AnyObject]{ 

    let sneakerName = dict["sneakerName"] as? String 
    self.sneakerArray.append(sneakerName) 

    //I didn't have to use the dispatch_async here 
    self.tableView.reloadData() 

    } 
}), withCancelBlock: nil) 
} 
Смежные вопросы