Estoy tratando de hacer una búsqueda desde mi base de datos para llenar una vista de colección, en orden de más reciente en la parte superior, hasta la más antigua. Intenté usar snap.children.allObjects.reversed(), pero mi aplicación se bloquea al cargar. Aquí está la función de búsqueda completa:

func fetchPosts() {

    let ref = FIRDatabase.database().reference()
    ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in

        let users = snapshot.value as! [String : AnyObject]

        for (_, value) in users {

            if let uid = value["uid"] as? String {

                if uid == FIRAuth.auth()?.currentUser?.uid {

                    if let followingUsers = value["following"] as? [String : String] {

                        for (_, user) in followingUsers {
                            self.following.append(user)
                        }
                    }
                    self.following.append(FIRAuth.auth()!.currentUser!.uid)

                    ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in

                        for postSnapshot in snap.children.allObjects.reversed() as! [FIRDataSnapshot] {
                            let value = postSnapshot.value as! [String : AnyObject]

                            if let userID = value["userID"] as? String {
                                for each in self.following {
                                    if each == userID {

                                        let posst = Post()
                                        if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String {

                                            posst.poster = poster
                                            posst.likes = likes
                                            posst.pathToImage = pathToImage
                                            posst.postID = postID
                                            posst.userID = userID
                                            if let people = value["peopleWhoLike"] as? [String : AnyObject] {
                                                for (_, person) in people {
                                                    posst.peopleWhoLike.append(person as! String)
                                                }
                                            }
                                            posts.append(posst)
                                        }
                                    }
                                }
                                self.collectionView.reloadData()
                            }
                        }
                    })
                    ref.removeAllObservers()
                }
            }
        }
    })
}

El error es EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0), con la advertencia Cast from 'ReversedRandomAccessCollection <[Any]>' (también conocido como 'ReversedRandomAccessCollection>') al tipo no relacionado '[FIRDataSnapshot]' siempre falla.

¿No es .reversed la forma de hacerlo? Tal como está, mi código sin .reversed carga las publicaciones en orden desde la más antigua en la parte superior, hasta la más nueva en la parte inferior. ¿Cómo puedo cambiarlo?

EDITAR: fragmento de Firebase de publicaciones:

"posts" : {
"-KfWzWv8rP38bUreDupj" : {
  "likes" : 1,
  "pathToImage" : "https://firebasestorage.googleapis.com/v0/b/cloudcamerattt.appspot.com/o/posts%2F1JSgke8QqFds4CxF2Z4MhuzbRoW2%2F-KfWzWv8rP38bUreDupj.jpg?alt=media&token=fef86bea-1ae2-4e1e-82fa-6209bc281a5e",
  "peopleWhoLike" : {
    "-KfX29jTcwaQDpkdIVX8" : "yI6NokUl2mTa7Uah4SgtAiulTJH2",
    "-KfXQJBRemZUCI2ieT94" : "MpnGvQj7ZOdz12zKD0bTeX1kp0B3"
  },
  "postID" : "-KfWzWv8rP38bUreDupj",
  "poster" : "Harry Potter",
  "userID" : "1JSgke8QqFds4CxF2Z4MhuzbRoW2"
},

EDITAR 2: Agregar una marca de tiempo

Agregué var timestamp: Int! a mi objeto Post, luego lo agregué a mi función de carga:

func uploadToFirebase() {
    AppDelegate.instance().showActivityIndicator()

    let uid = FIRAuth.auth()!.currentUser!.uid
    let ref = FIRDatabase.database().reference()
    let storage = FIRStorage.storage().reference(forURL: "gs://cloudcamerattt.appspot.com")
    let key = ref.child("posts").childByAutoId().key
    let imageRef = storage.child("posts").child(uid).child("\(key).jpg")
    let data = UIImageJPEGRepresentation(self.previewImage.image!, 0.6)
    var Timestamp: TimeInterval {
        return NSDate().timeIntervalSince1970 * 1000
    }

    let uploadTask = imageRef.put(data!, metadata: nil) { (metadata, error) in
        if error != nil {
            print(error!.localizedDescription)
            AppDelegate.instance().dismissActivityIndicator()
            return
        }

        imageRef.downloadURL(completion: { (url, error) in

            if let url = url {
                let feed = ["userID" : uid,
                            "pathToImage" : url.absoluteString,
                            "likes" : 0,
                            "poster" : FIRAuth.auth()!.currentUser!.displayName!,
                            "postID" : key,
                            "timestamp" : (0-Timestamp)] as [String : Any]

                let postFeed = ["\(key)" : feed]
                ref.child("posts").updateChildValues(postFeed)
                AppDelegate.instance().dismissActivityIndicator()

                let feedController = self.storyboard?.instantiateViewController(withIdentifier: "feedVC") as! FeedViewController
                feedController.navigationItem.setHidesBackButton(true, animated: false)

                self.tabBarController?.selectedIndex = 0
            }
        })
    }
    uploadTask.resume()
}

Luego agrégalo a mi búsqueda:

                                        let posst = Post()
                                        if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String, let timestamp = value["timestamp"] as? Int {

                                            posst.poster = poster
                                            posst.likes = likes
                                            posst.pathToImage = pathToImage
                                            posst.postID = postID
                                            posst.userID = userID
                                            posst.timestamp = timestamp

Función de recuperación actualizada (se produce un bloqueo Could not cast value of type 'FIRDataSnapshot' (0x10584eee8) to 'NSArray' (0x107b43dd8).):

func fetchPosts() {

    let ref = FIRDatabase.database().reference()
    ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in

        let users = snapshot.value as! [String : AnyObject]

        for (_, value) in users {

            if let uid = value["uid"] as? String {

                if uid == FIRAuth.auth()?.currentUser?.uid {

                    if let followingUsers = value["following"] as? [String : String] {

                        for (_, user) in followingUsers {
                            self.following.append(user)
                        }
                    }
                    self.following.append(FIRAuth.auth()!.currentUser!.uid)

                    for child in snapshot.children.reversed() {
                        let snap = child as! [FIRDataSnapshot]

                    ref.child("posts").queryOrdered(byChild: "timestamp").observeSingleEvent(of: .value, with: { (snap) in

                            if let userID = value["userID"] as? String {
                                for each in self.following {
                                    if each == userID {

                                        let posst = Post()
                                        if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String, let timestamp = value["timestamp"] as? Int {

                                            posst.poster = poster
                                            posst.likes = likes
                                            posst.pathToImage = pathToImage
                                            posst.postID = postID
                                            posst.userID = userID
                                            posst.timestamp = timestamp
                                            if let people = value["peopleWhoLike"] as? [String : AnyObject] {
                                                for (_, person) in people {
                                                    posst.peopleWhoLike.append(person as! String)
                                                }
                                            }
                                            posts.append(posst)
                                        }
                                    }
                                }
                                self.collectionView.reloadData()
                            }
                        })
                    }
                    ref.removeAllObservers()
                }
            }
        }
    })
}
-1
KingTim 21 mar. 2017 a las 16:00

2 respuestas

La mejor respuesta

Tratar

for child in snapshot.children.reversed() {
     let snap = child as! FIRDataSnapshot
     print(snap)
}

Está ordenando por clave que cargará la más antigua a la más nueva. Si desea invertir el orden y dejar que Firebase haga el trabajo pesado, use una técnica para el orden cronológico inverso publicado aquí

En Firebase, ¿cómo puedo consultar los 10 nodos secundarios más recientes?

Entonces es fácil hacer una consulta inversa ...

"posts" : {
   "-KfWzWv8rP38bUreDupj" : {
      "likes" : 1,
      "pathToImage" : "https:/...",
      "peopleWhoLike" : {
        "-KfX29jTcwaQDpkdIVX8" : "yI6NokUl2mTa7Uah4SgtAiulTJH2",
        "-KfXQJBRemZUCI2ieT94" : "MpnGvQj7ZOdz12zKD0bTeX1kp0B3"
      },
      "postID" : "-KfWzWv8rP38bUreDupj",
      "poster" : "Harry Potter",
      "timestamp" : -1.46081635550362E12,   //Just add this child
      "userID" : "1JSgke8QqFds4CxF2Z4MhuzbRoW2"
},

Y entonces

ref.child("posts").queryOrdered(byChild: "timestamp").observe(...

Además, el postID duplicado probablemente no sea necesario como niño, ya que también es la clave de la publicación.

1
Community 23 may. 2017 a las 12:02

Tienes razón en que necesitas lanzar algo en alguna parte, porque Swift solo sabe que comenzamos con una serie de Any. El problema es que estás lanzando la cosa equivocada en el lugar equivocado. Lanza postSnapshot al comienzo del interior del bucle for.

La forma de resolver este tipo de cosas es hacer un ejemplo de patio de recreo simplificado. Estás haciendo el equivalente de esto:

let arr : [Any] = [1,2,3]
for i in arr.reversed() as! [Int] { // crash
}

Lo que sabemos en ese ejemplo, sin embargo, no es algo acerca de arr.reversed(); es que i es un int. Esto esta bien:

let arr : [Any] = [1,2,3]
for i in arr.reversed() {
    if let i = i as? Int {
        // now it is safe to use `i`
    }
}

Tu caso es paralelo. Al comienzo del bucle for, debe lanzar postSnapshot a una captura de datos FIRE. Ahora puedes continuar.

0
matt 21 mar. 2017 a las 18:09