web-dev-qa-db-fra.com

Firebase: quand appeler removeObserverWithHandle dans swift

La documentation indique que vous devez appeler observeEventType:withBlock pour supprimer un observateur si vous n'en avez plus besoin. 

J'ai vu des exemples où il est appelé dans ViewDidDisAppear. Je trouve également du code Obj-C appelé cette méthode dans deinit, qui n'est pas nécessaire dans Swift.

Dans mon application simple, cependant, je souhaite que les données soient synchronisées tant que je suis dans l'application. Si tel est le cas, dois-je appeler observeEventType:withBlock jamais? 

J'ai vérifié le code d'exemple Chat-Swift sur le site Web de Firebase et je n'ai pas trouvé observeEventType:withBlock

Cela signifie-t-il qu'il est correct de ne pas appeler observeEventType:withBlock :. si je veux que l'observateur soit allumé lorsque l'application est en cours d'utilisation? 

Je vous remercie. 

METTRE À JOUR

Merci à Jay et David. Je vois qu'il est logique d'observer dans ViewWillAppear et de le supprimer dans ViewDidDisappear. 

Cependant, j'utilise observeEventType pour surveiller toute modification de valeur sur le nœud et met à jour l'interface utilisateur, le cas échéant. Si je le mets dans ViewWillAppear: 

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

    ref.observeEventType(.Value, withBlock: { snap in {
      // **update UI if there is any Value change** 
    })
  }

Le problème avec sa mise en viewWillAppear est que, il est appelé chaque fois que la vue apparaît, que la valeur change ou non. De ce fait, la capture instantanée est téléchargée et mon interface utilisateur est actualisée à chaque fois que je retourne à la vue. Cela devient contre-productif. 

J'ai aussi essayé ChildAdded/ChildRemoved, cependant, il ne retourne que le dernier nœud, pas le chemin de mon ref:

Par exemple, si j'ajoute ref/child1/child2/child3/value, ChildAdded ne renverra que child3/value. 

Donc, si je dois observer Value, il semble que le mettre dans ViewDidLoad est préférable? De cette manière, il obtient l'instantané une fois lorsque la vue est chargée et se répète chaque fois qu'il y a un changement, mais ne l'obtient pas uniquement parce que la vue apparaît. 

15
User5103156

Pour tirer parti de l'excellente réponse de @ Jay:

Dans UIViewController, créez une référence en tant que propriété. Initialiser une référence dans viewDidLoad. Observez les événements dans viewWillAppear. Supprimer les observateurs dans viewDidDisappear.

class MyViewController: UIViewController {

  var ref: Firebase!

  // Called only on load, great place to initialize
  override func viewDidLoad() {
    super.viewDidLoad()
    ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com/updates")
  }

  // Can be called many times to go on screen
  // Syncing should only occur when on view to conserve memory
  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    ref.observeEventType(.Value, withBlock: { snap in {
      // do something with the data 
    })
  }

  // Can be called many times to off screen
  // Remove observers on the ref to conserve memory
  override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    ref.removeAllObservers() 
  }

}

Par votre édition:

The problem with putting it in viewWillAppear is that, it gets called every time the view appears, regardless of Value change or not. Because of this, the snapshot is downloaded and my UI gets refreshed every time I return to the view. This becomes counterproductive.

Firebase est construit pour la vitesse. C’est le genre de choses que vous laissez au client car il dispose de plusieurs fonctionnalités qui gèrent ces situations.

Le client Firebase a une mise en cache intégrée. Sauf si vous téléchargez un mégaoctet de données dans viewDidAppear, la mise à jour est nominale. Lorsque l'observateur déclenche viewDidAppear, cela ne signifie pas nécessairement qu'il télécharge à nouveau les données. La fonction viewDidAppear est l’appartenance de vos observateurs.

Pour votre information, je suis un employé de Firebase qui travaille sur iOS. 

24
David East

observeEventType: withBlock est ce qui est utilisé pour observer un nœud.

Une fois que l'application observe un nœud, elle continue à l'observer sauf si vous quittez l'application ou demandez à Firebase de ne plus l'observer.

Pour arrêter d’observer, vous pouvez soit utiliser le descripteur qui a été renvoyé lorsque vous avez commencé à observer comme ceci: 

    //start observing and get a handle
FirebaseHandle handle = [ref observeEventType:FEventTypeValue withBlock:^(FDatasnapshot* snapshot) {
        // do some stuff with the snapshot data
    }];

    [ref removeObserverWithHandle:handle]; //stop observing using the handle

ou comme ça

[ref removeAllObservers];
6
Jay

Observer et arrêter d'observer à viewWillAppear () et viewWillDisappear () fonctionnerait, mais cela déclenche à nouveau les valeurs enfant ajoutées (en cas d'utilisation de .added/.value pour le type d'observation) lorsque le contrôleur de vue apparaît. 

Je préfère définir l'observation à viewDidLoad () et arrêter l'observation à deinit.

Certains disent que deinit n'est pas appelé après avoir défini l'observation, mais la raison en est que lorsque vous définissez l'observation, la fermeture de l'observateur est fortement conservée, de sorte que deinit ne sera jamais appelé. Vous pouvez définir faible ou non propriétaire à l'intérieur de la fermeture.

Voici un exemple.

class SomeViewController : UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    someRef.observe(.childAdded) { [weak self] (snapshot) in
      guard let weakSelf = self else { return }
      ...
    }
  }

  deinit {
    print("deinit called")
    someRef.removeAllObservers()
  }

}

N'oubliez pas d'écrire s'il vous plaît, ou deinit ne sera jamais appelé. J'espère que cela vous aidera.

1
Rian