【问题标题】:Why .childAdded is not called when new data is added? Firebase为什么添加新数据时不调用 .childAdded?火力基地
【发布时间】:2018-08-20 16:22:54
【问题描述】:

当数据在 /media 节点上更新时,我试图从 media 读取数据,但未调用 .observe(.childAdded
例如,我在 /media/-LKN1j_FLQuOvnhEFfao/caption 更新数据,但我从未在 observeNewMedia 中收到事件。
ViewDidLoad 完成时,我第一次可以毫无问题地读取数据。

第一步是下载用户数据,第二步是从 currentUser 获取locality,最后一步是在媒体上附加一个监听器.childAdded
我怀疑该事件没有被触发,因为fetchMediaDDatabaseRReference.users(uid: uid).reference().observe(.value 内部被调用

media
  -LKNRdP4ZsE3YrgaLB30
        caption: "santa"
        mediaUID: "-LKNRdP4ZsE3YrgaLB30"
        locality: "barking"

users
  Q6Dm3IMLNLgBH3ny3rv2CMYf47p1
       media
          -LKNReJCxgwtGRU6iJmV: "-LKNRdP4ZsE3YrgaLB30"
       email: "john@gmail.com"
       locality: "barking"


  //enables the programmer to create references to different childs in Firebase
  enum DDatabaseRReference {

   case root
   case users(uid:String)
   case media  //to store photos

    func reference() -> DatabaseReference {
       return rootRef.child(path)
   }


  //return root reference to our database
   private var rootRef: DatabaseReference {
       return Database.database().reference()
  }

private var path: String {

      switch self { //self is the enum DDatabaseReference
       case .root:
         return ""

       case .users(let uid):
         return "users/\(uid)"

       case .media:
          return "media"        
       }
    }

  }//end of enum DatabaseReference




 class NewsfeedTableViewController: UITableViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

            //observe ~/users/uid
    DDatabaseRReference.users(uid: uid).reference().observe(.value, with: { (snapshot) in

        DispatchQueue.main.async {
            if let userDict = snapshot.value as? [String : Any] {
                self.currentUser = UserModel(dictionary: userDict)
                self.fetchMedia()
                self.tableView.reloadData()
            }
        }
    })

  }

    func fetchMedia() {   

 Media.observeNewMedia((currentUser?.locality)!) { (newMedia) in

        //check if newly downloaded media is already in media array
        if !self.media.contains(newMedia) {
            self.media.insert(newMedia, at: 0)
            self.tableView.reloadData()
        }else {
            //remove old media and add the newly updated one
            guard let index = self.media.index(of: newMedia) else {return}
            self.media.remove(at: index)
            self.media.insert(newMedia, at: 0)
            self.tableView.reloadData()
        }
    }
}

 }//end of NewsfeedTableViewController


 class Media {

class func observeNewMedia(_ userLocality: String, _ completion: @escaping (Media) -> Void) {


    DDatabaseRReference.media.reference().queryOrdered(byChild: "locality").queryEqual(toValue: userLocality).observe(.childAdded, with: { snapshot in
        guard snapshot.exists() else {
       print("no snap ")
        return}
        print("snap is \(snapshot)")
        let media = Media(dictionary: snapshot.value as! [String : Any])
        completion(media)
    })
  }
} //end of class Media

【问题讨论】:

  • 您正在通过子“位置”观察一个节点,该节点似乎不存在于问题中包含的 Firebase 结构中。目前尚不清楚实际上正在观察/查询哪个节点。问题说您正在尝试观察媒体节点,但您添加了一个查询来“过滤”结果,而不仅仅是一个观察者。此外,您正在使用 media.reference() 但不清楚原因。
  • @Jay 我创建了一个枚举 DDatabaseRReference 以便更轻松地创建对 firebase 的引用。在 viewDidLoad users/userUID 中观察到。初始化 UserModel 并且我拥有 locality 属性的值后,将对 media/mediaUID 进行查询,同时将 childAdded 事件附加到 firebase 引用。我想要的是每次在 /media/mediaUID 添加或修改孩子或其后代孩子时从 firebase 获取更新。换句话说,如果media/-LKNRdP4ZsE3YrgaLB30/caption 接收到一个新值,我想接收那个数据。
  • mediaUID 在 Firebase 结构中没有这样的子级。它显示 mediaUID: "-LKNRdP4ZsE3YrgaLB30" 所以它的孩子是 -LKNRdP4ZsE3YrgaLB30 的字符串。我认为您可能希望 .observe 使用 .childAdded 到媒体节点以在将孩子添加到该节点时获取事件。此外,没有理由存储与父节点具有相同值的子节点,因为 parentNode 是键,它始终可从 snapshot.key 获得。
  • 问题中有相当多的代码,因此不清楚您要做什么。这是一个猜测——让我知道这是否准确;对于当前登录的用户,您希望在从媒体节点添加、更改或删除新媒体时接收事件?然后这些更改应反映在 self.media 数组中,以便 UI 可以相应更新
  • 是的,这正是我想要的。对于当前登录的用户,我想在添加、更改或删除新媒体时接收事件: media/mediaUID 。 mediaUID 是我用来识别每个媒体对象的值。您可以看到该值在 /users LKNRdP4ZsE3YrgaLB30 中出现一次,然后在 /media 中再次出现。

标签: swift firebase firebase-realtime-database


【解决方案1】:

让我们首先更新结构,使其更易于查询

假设一个用户节点

users
   -Q6Dm3IMLNLgBH3ny3rv2CMYf47p1  //this is each users uid
      email: "john@gmail.com"
      locality: "barking"

以及一个包含所有用户媒体的媒体节点

media
   -abcdefg12345 //node created with childByAutoId
      caption: "santa"
      for_uid: -Q6Dm3IMLNLgBH3ny3rv2CMYf47p1 //matches the uid in the /users node

然后是我们的主视图控制器,其中包含对 Firebase 的引用并将用户登录

class ViewController: UIViewController {
   var ref: DatabaseReference!

   override func viewDidLoad() {
      super.viewDidLoad()
      self.ref = Database.database().reference()
      //log user in which will populate the Auth.auth.currentUser variable
    }
   .
   .
   .

我们需要一个对象来存储媒体,然后是一个数组来保存这些对象

class MediaClass {
    var key = ""
    var caption = ""

    init(k: String, c: String) {
        self.key = k
        self.caption = c
    }
}

var mediaArray = [MediaClass]()

然后设置观察者,当该用户的媒体被添加、更改或删除时,将在数组中添加、更新或删除。

let thisUid = Auth.auth().currentUser?.uid
let mediaRef = self.ref.child("media")

let queryRef = mediaRef.queryOrdered(byChild: "for_uid").queryEqual(toValue: thisUid)

queryRef.observe(.childAdded, with: { snapshot in
    let dict = snapshot.value as! [String: Any]
    let key = snapshot.key
    let caption = dict["caption"] as! String
    let m = MediaClass.init(k: key, c: caption)
    self.mediaArray.append(m)
    self.tableView.reloadData()
})

queryRef.observe(.childChanged, with: { snapshot in
    let dict = snapshot.value as! [String: Any]
    let key = snapshot.key
    let caption = dict["caption"] as! String
    let index = self.mediaArray.index { $0.key == key } //locate this object in the array
    self.mediaArray[index!].caption = caption //and update it's caption
    self.tableView.reloadData()
})

//leaving this an an exercise
queryRef.observe(.childRemoved....

请注意,我们通过查询向媒体节点添加了 .childAdded、.childChanged 和 .childRemoved 事件,因此应用将接收的唯一事件是与该用户相关的事件。

还要注意没有错误检查,所以需要添加。

【讨论】:

  • MediaClassUserModel 都有一个名为:locality 的属性。我只想在 user.locality == media.locality 时获得 FirDataEvent 。为了做到这一点,第一步是 1. 下载用户子项(当我登录时,我只得到uid),2. 获取用户的位置和 3. 创建如下查询:@987654330 @。我应该创建一个计算属性,当它被设置时,它将调用 queryRef.observe(childAdded,queryRef.observe(.childChanged ?这是正确的方法吗?
  • @bibscy 因此,您只想在 media.locality 等于该用户位置节点中的内容的位置时为用户获取事件?你能详细说明一下吗?什么时候该用户的媒体节点不匹配本地?
  • 这正是我想要的,为了实现这一点,我用一个名为 currentUser 的 setter 创建了一个计算属性。设置此属性后,我附加queryRef.observe(childAddedqueryRef.observe(.childChanged 这是正确的方法吗?它似乎正在工作。
  • 我很高兴它的工作,这可能意味着它是正确的方法。如果您遇到其他问题,请告诉我们。
  • 我刚才问了一个关于以编程方式删除/撤销动态 Firebase 链接的问题,但是,我无法得到答案 stackoverflow.com/questions/51860802。非常感谢您一直以来的帮助:)
猜你喜欢
  • 2016-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多