2017-09-14 13 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) 
    } 
} 

と私はのエラーを取得:

はの値をキャストできませんでした'NSDictionary'(0x1060b92d8)に '__NSCFString'(0x1060b84f0)を入力します。 snapshotValueの印刷の説明: ([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つの子ノードがあります。

初期:それはそのようなことをするだろうオブザーバが呼び出されます:

あなたはあなたが今の子供3

を取得し、子供2

を取得し、子1

を取得し、別の子ならばが追加されました:

新しい子:オブザーバーが呼び出されました:

あなたは子供4

など。

+1

を取得するには、このいただきありがとうございます!ちょうど明らかであるように、私はもともと、.childAddedがすべての既存の子を一度走ってから、追加されたすべての子のリスナーとして振る舞ったと考えました。それは間違っていますか?次に、 'viewDidLoad'で' loadAnnotations'関数を呼び出し、その下で 'annotationChildAdded'を呼び出しますか? – zachenn

+0

よろしくお願いします。あなたは正しいのですが、最初はすべての既存の子を一度実行してから、追加されたすべての子がトリガーされます。しかしどちらの場合も、その特定の子のみを返し、内部にすべてのコンテンツを持つ親ノード全体を返しません。 – Alex

+0

2番目の質問では、viewDidAppearメソッドで子追加メソッドを記述し、viewDidDisAppearメソッドですべてのオブザーバを削除することをお勧めします。また、childAddedオブザーバを呼び出す前に、配列内にあるすべての要素を削除して、ビューコントローラが表示されるたびに重複を避ける必要があります。 – Alex

関連する問題