2017-09-18 67 views
0

現在,我很迷惑firebase,觀察使用childAdded數據事件類型。我之所以使用childAdded來觀察我的firebase,是因爲我想讓我的列表頁面動態 firebase是否有新的數據插入。如何檢測firebase觀察childAdded是否在達到queryLimit時停止調用?

而我的問題是如何知道觀察到達queryLimit時停止調用?因爲我有一個指標,我想在達到queryLimit時關閉它。

我的火力點以下結構:

root { 
    talkID1(id by auto create) { 
    attribute1 ... 
    attribute2 ... 
    attribute3 ... 
    time 
    } 

    talkID2(id by auto create){ 
    ... 
    time 
    } 

    ... // many talk ID which auto create by firebase 

}

正如我所知道的,如果用childAdd將觀察,數據將一個孩子的孩子在通話將數據傳回。所以如果我有N數據在firebase,我想它會叫N < = 5次,對不對?

我完成如下處理:

func receiveIfExist(completion: @escaping (_ data: (My data type) -> Void) { 
    let requestWithQuery = Database.database.reference().child("root").queryOrdered(byChild: "time") 

    requestWithQuery.queryLimited(toLast: 5).observe(.childAdded, with: { (snapshot) in 
     guard let value = snapshot.value as? [String: Any] else { return } 

     self.getSingleTalkInfo(key: snapshot.key, value: value, completion: { (data) in 
      completion(data) 
     }) 
    }) 
} 

我打電話receiveIfExist此功能在viewDidLoad中()。

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.myIndicator.startAnimating() // start running indicator 
    self.receiveIfExist { (data) in 

     self.handleTalk(with: data) // do something with request data 
     self.myIndicator.stopAnimating() // WEIRD!!!! Please look comments below 

     /* 
      I think it can not be added here because this completion will call N<=5 times just what I said before. 
      I think it should detect what my queryLimit data is and check the request data is this queryLimit data or not. 
      If yes then stop indicator animating, if not then keep waiting the queryLimit reach. 
     */ 
    } 
} 

如何檢測觀察是否達到queryLimit?

如果我能檢測到,那麼當它到達時我可以關閉我的指示器。

謝謝!

回答

1

queryLimited(toLast:5)

手段(以更簡單的話)請獲得最後的5個值

(順序是由您的查詢的前一部分決定) 1.現在,由於您按次分類數據,因此最近5次的值將被檢索,因此您的觀察者將被觸發5次

2.請注意,如果您有少於5條說2名的記錄,那麼將只有兩次,因爲上限是5,而不是下限

的另一點是,如果一個新的是說觸發孩子被添加,並且當您根據時間再次對項目進行排序並且新孩子是最後5個項目之一時,則此觀察者將再次被觸發。

所以要得到查詢的限制,你可以使你的代碼是這樣一些變化:然後使用上述功能如下

func receiveIfExist(completion: @escaping (data: YourType, limitCount: Int) -> Void) { 
    let requestWithQuery = Database.database.reference().child("root").queryOrdered(byChild: "time") 

    requestWithQuery.queryLimited(toLast: 5).observe(.childAdded, with: { (snapshot) in 
     guard let value = snapshot.value as? [String: Any] else { return } 

     self.getSingleTalkInfo(key: snapshot.key, value: value, completion: { (data) in 
      self.index = self.index + 1 
      completion(data, self.index) 
     }) 
    }) 
} 

var index = 0 
override func viewDidLoad() { 
    super.viewDidLoad() 

    self.myIndicator.startAnimating() // start running indicator 
    self.receiveIfExist { (data, limitCount) in 

     self.handleTalk(with: data) // do something with request data 
     if limitCount == 5 { 
      self.myIndicator.stopAnimating() 
     } 


    } 
} 

更新:

由於凱文提出的非常好的觀點,如果我們只說兩條記錄並且索引不會等於5 a,那麼上面的解決方案就會失敗第二myIndicator不會停止動畫,這在我腦海

一種解決方案是這樣的:

首先,我們得到了孩子計數使用observeSingleEvent

func getChildrenCount(completion: @escaping (_ childrenCount: Int) -> Void){ 
    Database.database.reference().child("root").observeSingleEvent(of:.value with: { (snapshot) in 

        completion(snapshot.children.count) 

    } 
} 

然後我們運用查詢來獲取最後5項目:

func receiveIfExist(completion: @escaping (data: YourType, limitCount: Int) -> Void) { 
     let requestWithQuery = Database.database.reference().child("root").queryOrdered(byChild: "time") 

     requestWithQuery.queryLimited(toLast: queryLimit).observe(.childAdded, with: { (snapshot) in 
      guard let value = snapshot.value as? [String: Any] else { return } 

      self.getSingleTalkInfo(key: snapshot.key, value: value, completion: { (data) in 
       self.index = self.index + 1 
       completion(data, self.index) 
      }) 
     }) 
    } 

然後用這個數在您的代碼如下:

var index = 0 
var childrenCount = 0 
var queryLimit = 5 
override func viewDidLoad() { 
    super.viewDidLoad() 

    self.myIndicator.startAnimating() // start running indicator 
    self.getChildrenCount {(snapChildrenCount) in 
     self.childrenCount = snapChildrenCount 

     self.receiveIfExist { (data, limitCount) in 

     self.handleTalk(with: data) // do something with request data 
     if (self.childrenCount < self.queryLimit && limitCount == self.childrenCount) || limitCount == self.queryLimit { 
      DispatchQueue.main.async { 
        self.myIndicator.stopAnimating() 
      } 

     } 


    } 

    } 

} 
+0

謝謝您回覆。但我有一個問題,就是你在第二點中所說的「如果我的根中只有兩條記錄,那麼它會被觸發兩次?」如果是這樣,這行「self.index = self.index + 1」只會被調用兩次,並導致limitCount的總和只有2? – Kevin

+0

它可能會導致limitCount只有2,並可能不會阻止myIndi​​cator,對不對? – Kevin

+0

@Kevin是的你是對的,我認爲我們不能真正知道記錄的數量,所以上面的解決方案是部分正確的我想,我沒有嘗試過,請嘗試它並分享輸出,你學到了什麼,謝謝 – 3stud1ant3

0
func receiveIfExist(limitCount: UInt, completion: @escaping (data: MyDataType) -> Void) { 
    let requestWithQuery = Database.database.reference().child("root").queryOrdered(byChild: "time") 

    requestWithQuery.queryLimited(toLast: limitCount).observe(.childAdded, with: { (snapshot) in 
     guard let value = snapshot.value as? [String: Any] else { return } 

     self.getSingleTalkInfo(key: snapshot.key, value: value, completion: { (data) in 
      completion(data) 
     }) 
    }) 
} 

我也做這個功能只觀察一個孩子的價值

let requestTalks = Database.database.reference().child("root")  

func getSingleTalk(by key: String = "", at limitType: TalkLimitType, completion: @escaping (_ eachData: MyDataType) -> Void) { 

    var requestSingleTalk: DatabaseQuery { 
     switch limitType { 
     case .first : 
      return self.requestTalks.queryOrdered(byChild: "time").queryLimited(toFirst: 1) 

     case .last : 
      return self.requestTalks.queryOrdered(byChild: "time").queryLimited(toLast: 1) 

     case .specificKey : 
      return self.requestTalks.child(key) 
     } 
    } 

    requestSingleTalk.observeSingleEvent(of: .value, with: { (snapshot) in 

     if limitType == .specificKey { 
      guard let value = snapshot.value as? [String: Any] else { return } 

      self.getSingleTalkInfo(key: snapshot.key, value: value, completion: { (data) in 
       completion(data) 
      }) 
     } else { 
      guard let snapshotValue = snapshot.value as? NSDictionary, 
        let eachTalkKey = snapshotValue.allKeys[0] as? String, 
        let eachTalkValue = snapshotValue.value(forKey: eachTalkKey) as? [String: Any] else { return } 

      self.getSingleTalkInfo(key: eachTalkKey, value: eachTalkValue, completion: { (data) in 
       completion(data) 
      }) 
     } 
    }) 
} 

結果,我可以做這樣的事情在我viewDidLoad中()

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.myIndicator.startAnimating() 
    self.receiveIfExist(limitCount: 5) { (eachData) in 
     self.handleTalk(with: eachData) 
     self.getSingleTalk(at: .last, completion: { (lastData) in 
      if eachData.keyID == lastData.keyID{ 
       DispatchQueue.main.async { 
        self.myIndicator.stopAnimating() 
       } 
      } 
     }) 
    } 
} 
+0

這是否適用於您,是否測試了它?如果是,那麼我只想提出一件事情,在主隊列上應該對每個UI進行更改,因此只需在self.myIndi​​cator.stopAnimating()內添加'async' '像這樣的塊:'DispatchQueue.main.async {self.myIndi​​cator.stopAnimating() }' – 3stud1ant3

+0

哦,是的,我很抱歉,我忘了它。 – Kevin

相關問題