What exactly is deinit doing here? And why?

512 Views Asked by At

My Question has to do with the sample code provided for Firebase. You can find it on Github or in the Documentation. Anyway, I don't really understand what the "deinit" on the database reference is doing. I read the deinit swift documentation here. I think I understand the purpose of using a deinit, but I'm not sure how it works in this case.

let kBannerAdUnitID = "ca-app-pub-3940256099942544/2934735716"

@objc(FCViewController)
class FCViewController: UIViewController, UITableViewDataSource, UITableViewDelegate,
    UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate,
        InviteDelegate {

  // Instance variables
  @IBOutlet weak var textField: UITextField!
  @IBOutlet weak var sendButton: UIButton!
  var ref: DatabaseReference!
  var messages: [DataSnapshot]! = []
  let posts = [Post]()

  var msglength: NSNumber = 10
  fileprivate var _refHandle: DatabaseHandle!

  var storageRef: StorageReference!
  var remoteConfig: RemoteConfig!

  @IBOutlet weak var banner: GADBannerView!
  @IBOutlet weak var clientTable: UITableView!

  override func viewDidLoad() {
    super.viewDidLoad()

    self.clientTable.register(UITableViewCell.self, forCellReuseIdentifier: "tableViewCell")

    configureDatabase()
    configureStorage()
    configureRemoteConfig()
    fetchConfig()
    loadAd()
    logViewLoaded()
  }

    deinit {

        // NOT REALLY SURE WHAT THIS DOES
        if let refHandle = _refHandle {
            self.ref.child("messages").removeObserver(withHandle: _refHandle)
        }
    }

func configureDatabase() {
    ref = Database.database().reference()
    // Listen for new messages in the Firebase database
    _refHandle = self.ref.child("messages").observe(.childAdded, with: { [weak self] (snapshot) -> Void in
        guard let strongSelf = self else { return }

        // EACH SNAPSHOT IS PLACED IN THE MESSAGES ARRAY
        strongSelf.messages.append(snapshot)

        // MAKE THE NUMBER OF ROWS IN THE FEED == THE NUMBER OF SNAPSHOTS
        strongSelf.clientTable.insertRows(at: [IndexPath(row: strongSelf.messages.count-1, section: 0)], with: .automatic)
    })
}
1

There are 1 best solutions below

0
On BEST ANSWER

During initialization, your view controller adds a childAdded observer to a given Firebase database node. The passed in closure would still be called even after the view controller was long gone (i.e., deallocated). Firebase keeps a strong reference to it (and a weak reference to your view controller, by the way). This unnecessary calling might not be a major issue (yet!), but it's wrong nevertheless.

The deinit code prevents that from happening.

The deinitializer is called immediately before your view controller is deallocated. As such, it provides a nice place to remove that observer from the aforementioned database node. The observer (reference) is stored in the _refHandle property.

By the way, you could simplify your observer removing code to:

if let refHandle = _refHandle {
    self.ref.removeObserver(withHandle: _refHandle)
}

you don't need to call removeObserver on the same node it was registered on.


Weak View Controller. The [weak self] qualifier, in the aforementioned closure, is what specifies that Firebase should keep only a weak reference to your view controller. This is crucial to ensure that the view controller is properly released from memory when no longer needed. Without it, your deinit would never be called!