0

我的问题与为 Firebase 提供的示例代码有关。您可以在Github文档中找到它。无论如何,我真的不明白数据库参考上的“deinit”在做什么。我在这里阅读了 deinit swift 文档。我想我理解使用 deinit 的目的,但我不确定在这种情况下它是如何工作的。

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)
    })
}
4

1 回答 1

2

在初始化期间,您的视图控制器将childAdded观察者添加到给定的 Firebase 数据库节点。即使在视图控制器早已消失(即,解除分配)之后,传入的闭包仍然会被调用。Firebase 保持对它的强引用(顺便说一下,对视图控制器的引用)。这种不必要的调用可能不是一个主要问题(还没有!),但它仍然是错误的。

deinit代码可以防止这种情况发生。

在释放视图控制器之前立即调用 deinitializer 。因此,它提供了一个从上述数据库节点中删除该观察者的好地方。观察者(参考)存储在_refHandle属性中。

顺便说一句,您可以将观察者删除代码简化为:

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

您不需要在注册它removeObserver同一节点上调用。


弱视图控制器。前面提到的闭包中的[weak self]限定符指定 Firebase 应该只保留对视图控制器的弱引用。这对于确保视图控制器在不再需要时从内存中正确释放至关重要。没有它,你deinit永远不会被调用!

于 2017-05-20T20:16:48.920 回答