2017-09-14 57 views
1

現在我有.observeSingleEvent(of: .value),我的所有註釋裝載到地圖:.oberve(.childAdded)產生錯誤,而.observeSingleEvent(作者:.value的)是不是

func loadAnnotations() { 

    if let uid = Auth.auth().currentUser?.uid { 
     uidRef.child(uid).child("annotations").observeSingleEvent(of: .value, with: { (snapshot) in 

      for item in snapshot.children { 

       // annotationListItem is a struct I created 
       let annotationItem = AnnotationListItem(snapshot: item as! DataSnapshot) 

       let doubleLatitude = Double(annotationItem.mapViewLatitude!) 
       let doubleLongitude = Double(annotationItem.mapViewLongitude!) 
       let coordinate = CLLocationCoordinate2DMake(doubleLatitude!, doubleLongitude!) 

       let annotation = MKPointAnnotation() 
       annotation.coordinate = coordinate 
       annotation.title = annotationItem.annotationTitle 
       annotation.subtitle = annotationItem.annotationSubtitle 
       self.mapView.addAnnotation(annotation) 

      } 
     }, withCancel: nil) 

    } 
} 

現在我要地圖更新每次用戶添加一個新的註釋,所以我放在完全相同的代碼,但與.observe(.childAdded)

func annotationChildAdded() { 

    if let uid = Auth.auth().currentUser?.uid { 
     uidRef.child(uid).child("annotations").observe(.childAdded, with: { (snapshot) in 

      for item in snapshot.children { 
       let annotationItem = AnnotationListItem(snapshot: item as! DataSnapshot) 

       let doubleLatitude = Double(annotationItem.mapViewLatitude!) 
       let doubleLongitude = Double(annotationItem.mapViewLongitude!) 
       let coordinate = CLLocationCoordinate2DMake(doubleLatitude!, doubleLongitude!) 

       let annotation = MKPointAnnotation() 
       annotation.coordinate = coordinate 
       annotation.title = annotationItem.annotationTitle 
       annotation.subtitle = annotationItem.annotationSubtitle 
       self.mapView.addAnnotation(annotation) 
      } 

     }, withCancel: nil) 
    } 
} 

我得到的錯誤:的

無法施展值鍵入'__NSCFString'(0x1060b84f0)爲'NSDictionary'(0x1060b92d8)。 快照的打印說明值: ([String:AnyObject])snapshotValue =變量不可用>

如何解決此問題?

UPDATE

.observe(.value)作品。但我仍然想知道爲什麼.childAdded

回答

0

這裏的問題是,.observeSingleEvent(of: .value).observe(.childAdded)不會返回相同的東西。

當您致電.observe(.value)時,它會返回事件發生時所有內容的全部節點。

但是,當您使用.observe(.childAdded)時,它將僅返回添加到指定路徑(即,添加的子項)的內容。

你可以看到在兩種方法中做print(snapshot),你會很容易看到差異。

因此,要使用.childAdded訪問您的數據,您不需要遍歷所有孩子,就像使用.observeSingleEvent(of:.value)所做的那樣。相反,你會怎麼做:

 guard let uid = Auth.auth().currentUser?.uid else { 
      return 
     } 

     uidRef.child(uid).child("annotations").observe(.childAdded, with: { (snapshot) in 

       let annotationItem = AnnotationListItem(snapshot: item as! DataSnapshot) 

       let doubleLatitude = Double(annotationItem.mapViewLatitude!) 
       let doubleLongitude = Double(annotationItem.mapViewLongitude!) 
       let coordinate = CLLocationCoordinate2DMake(doubleLatitude!, doubleLongitude!) 

       let annotation = MKPointAnnotation() 
       annotation.coordinate = coordinate 
       annotation.title = annotationItem.annotationTitle 
       annotation.subtitle = annotationItem.annotationSubtitle 
       self.mapView.addAnnotation(annotation) 
      } 

     }) 

另外,我勸你不要逼投像item as! DataSnapshot您的項目,因爲如果你在你的數據庫錯過了什麼應用程序只會崩潰。

相反,我會做這樣的話,用後衛聲明:

guard let uid = Auth.auth().currentUser?.uid else { 
    return 
} 

uidRef.child(uid).child("annotations").observe(.childAdded, with: { [weak self] (snapshot) in 

     let annotationKey = snapshot.key 

     guard let longitude = snapshot.childSnapshot(forPath: "longitude").value as? NSNumber else { return } 

     guard let latitude = snapshot.childSnapshot(forPath: "latitude").value as? NSNumber else { return } 

     guard let title = snapshot.childSnapshot(forPath: "title").value as? String else { return } 

     // Here it really depends on how your database look like. 

     // ... 

     // Create your annotation item using the values from the snapshot : 

     let annotation = AnnotationListItem(id: annotationKey, title: title, longitude: longitue, latitude: latitude) 

     // Finally add the data to an array : 

     self?.annotationsArray.append(annotation) 

     // Or directly to your mapView : 

     self?.mapView.addAnnotation(annotation) 

}) 

只要讓我知道,如果有幫助; d

更新

例如,假設您您的數據庫中最初有3個子節點。它會做這樣的事情:

初始:觀測得到所謂:

你的孩子1

你的孩子2

你的孩子3

現在,如果另一個孩子添加:

新生兒:觀察員被調用:

你得到孩子4

等。

+1

謝謝!爲了清楚起見,我原本以爲'.childAdded'曾經遍歷所有現有的孩子,然後充當每個添加的孩子的監聽者。那是錯的嗎?其次,我應該在'viewDidLoad'中調用我的'loadAnnotations'函數,然後在它下面調用'annotationChildAdded'? – zachenn

+0

不客氣@zachenn!你是對的,它最初確實貫穿所有現有的孩子,然後觸發每個孩子添加。但是在這兩種情況下,它只會返回該特定的子項,而不會返回包含其所有內容的整個父節點。我更新了我的答案,以便更容易理解 – Alex

+0

對於第二個問題,我建議您在viewDidAppear方法中編寫子添加方法,並確保刪除viewDidDisappear方法中的所有觀察者。此外,在調用childAdded觀察者之前,您需要刪除陣列內的所有元素,以避免每次出現視圖控制器時都出現重複。 – Alex

相關問題