通过一次通话

时间:2017-03-13 13:34:05

标签: ios swift firebase firebase-realtime-database firebase-storage

我有一个集合视图,显示从我的一个视图控制器FeedViewController中的Firebase获取的图像 - 在控制器中viewDidLoad我使用fetchPosts函数获取图像(我也删除了)在获取之前的所有帖子,否则他们出现两次 - 让我知道这不是一个好方法这样做:

override func viewDidLoad() {
    super.viewDidLoad()

    posts.removeAll()
    following.removeAll()
    fetchPosts()
}

我有几个"显示" segues to FeedViewController,所有这些都正常工作,Feed尽可能地加载 - 所有图像都出现一次。但是,我有一个在用户选择要上传的图像后调用的segue,它会以某种方式导致图像被提取(因此出现在CV中)两次。 segue在上传函数中调用:

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)
    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,
                            "author" : FIRAuth.auth()!.currentUser!.displayName!,
                            "postID" : key] as [String : Any]

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

                self.performSegue(withIdentifier: "showFeed", sender: nil)
            }
        })
    }
    uploadTask.resume()
}

似乎segue在该函数内的正确位置(如果我错了,再次纠正我),但就像我说的,当用户选择图像并点击帖子按钮时,上面的功能是被叫,它们被带回到饲料控制器,它们发布的图像以及当前饲料中的所有其他图像显示两次(有时三次)。我不确定为什么会这样。如果我离开Feed并返回(通过其他segues到Feed),图像会再次正确显示 - 即所有图像只出现一次。

因此,由于其他segues工作正常,我觉得这个问题不在segue中,或者FeedViewController处理提取&填充简历(尽管可能效率低下)。它必须在上传功能中。就像我说的那样,我无法在这个功能中看到更合理的地方来调用segue。谁能看到我在这里失踪的东西?

编辑:我的fetchPosts()功能:

func fetchPosts() {

    var posts = [Post]()

    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 {
            // get uid as string
            if let uid = value["uid"] as? String {
                // check to make sure uids match
                if uid == FIRAuth.auth()?.currentUser?.uid {
                    // check for followers
                    if let followingUsers = value["following"] as? [String : String] {
                        // loop through those and add them to "following" array
                        for (_, user) in followingUsers {
                            self.following.append(user)
                        }
                    }
                    // add current user to that array also so you can see your own posts
                    self.following.append(FIRAuth.auth()!.currentUser!.uid)

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

                        let postsSnap = snap.value as! [String : AnyObject]

                        for (_, post) in postsSnap {
                            if let userID = post["userID"] as? String {
                                for each in self.following {
                                    if each == userID {
                                        // here are the posts that the user should see (his own and his following)
                                        let posst = Post()
                                        if let author = post["author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {

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

1 个答案:

答案 0 :(得分:3)

当您使用removeAllObservers时,它会继续监控更改。您之后使用.observeSingleEvent因此我假设您只需要一次数据。在这种情况下,最好使用.value,因为这只会获取一次数据。

这就是我认为正在发生的事情,如果没有看到代码执行就很难分辨。由于Firebase是异步的,因此代码会继续执行,并且不会等待Firebase命令完成。我认为在updateChildValues实际完成之前,您正在使用Feed。到达FeedViewController后,您清空了集合并加载了数据。数据将开始加载,在加载时,将添加帖子。这再次触发.observe,因为数据库中发生了某些变化,导致它多次运行。由于您只在viewDidLoad中清除了您的收藏集,因此重复的帖子会附加到您的收藏中。

要避免这种情况,请将observeSingleEvent替换为removeAll(),或者不要使用viewDidLoad中的.observe,而是在{{1}}内使用{{1}}我认为必须在主队列上这样做。