Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 从一次调用中提取两次Firebase数据_Ios_Swift_Firebase_Firebase Realtime Database_Firebase Storage - Fatal编程技术网

Ios 从一次调用中提取两次Firebase数据

Ios 从一次调用中提取两次Firebase数据,ios,swift,firebase,firebase-realtime-database,firebase-storage,Ios,Swift,Firebase,Firebase Realtime Database,Firebase Storage,我有一个集合视图,在其中一个视图控制器中显示从Firebase获取的图像,FeedViewController——在该控制器中viewDidLoad我使用fetchPosts功能获取图像(我也会在获取之前删除所有帖子,否则它们会出现两次-如果这不是一个好方法,请告诉我): 我有几个“show”segue指向FeedViewController,所有这些都可以正常工作,feed按它应该的方式加载-所有图像只显示一次。但是,我有一个segue,在用户选择要上传的图像后调用,它以某种方式导致图像被提取

我有一个集合视图,在其中一个视图控制器中显示从Firebase获取的图像,
FeedViewController
——在该控制器中
viewDidLoad
我使用
fetchPosts
功能获取图像(我也会在获取之前删除所有帖子,否则它们会出现两次-如果这不是一个好方法,请告诉我):

我有几个“show”segue指向
FeedViewController
,所有这些都可以正常工作,feed按它应该的方式加载-所有图像只显示一次。但是,我有一个segue,在用户选择要上传的图像后调用,它以某种方式导致图像被提取(并因此出现在简历中)两次。在此上载函数中调用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在该函数中的正确位置(如果我错了,请再次纠正我),但正如我所说,当用户选择一个图像并点击post按钮并调用上述功能时,它们将被带回提要控制器,并且它们发布的图像以及当前提要中的所有其他图像将显示两次(有时是三次)。我不知道为什么会发生这种情况。如果我离开源并返回(通过其他序列返回源),图像将再次正确显示-即所有图像仅显示一次

因此,由于其他分段工作正常,我觉得问题不在分段中,也不在
FeedViewController
处理获取和填充CV的方式中(尽管可能效率低下).它必须在上传功能中。就像我说的,我看不到在该功能中调用segue的任何逻辑位置。有人能看到我缺少的东西吗

编辑:My
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()
                }
            }
        }
    })
}

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

以下是我认为正在发生的事情,如果不看到代码执行,很难判断。由于Firebase是异步的,代码会一直执行,不会等待Firebase命令完成。我认为你在UpdateChildValue实际完成之前就开始了订阅源。到达FeedViewController后,你清空了你的收藏打开并加载数据。数据将开始加载,加载时,将添加帖子。这再次触发了
.value
,因为数据库中发生了更改,导致它运行多次。而且,由于您仅在viewDidLoad中清除了集合,重复的帖子将附加到集合中。


要避免这种情况,请将
.observeSingleEvent
替换为
observeSingleEvent
,或者在
视图中使用
removeAll()
,而不是在
的内部使用它。observey
(尽管我认为您必须在主队列中执行此操作).

当您使用
时。观察
它将持续监视更改。之后您使用
RemoveAllObserver
,因此我假设您只需要一次数据。在这种情况下,最好使用
.observeSingleEvent
,因为这样只会获取一次数据

以下是我认为正在发生的事情,如果不看到代码执行,很难判断。由于Firebase是异步的,代码会一直执行,不会等待Firebase命令完成。我认为你在UpdateChildValue实际完成之前就开始了订阅源。到达FeedViewController后,你清空了你的收藏打开并加载数据。数据将开始加载,加载时,将添加帖子。这再次触发了
.value
,因为数据库中发生了更改,导致它运行多次。而且,由于您仅在viewDidLoad中清除了集合,重复的帖子将附加到集合中。


要避免这种情况,请将
.observeSingleEvent
替换为
observeSingleEvent
,或者在
视图中使用
removeAll()
,而不是在
中使用它。observey
(尽管我认为您必须在主队列上执行此操作)。

您能给我们看一下fetchPosts()吗方法?请把它放在您的问题中。@PieterLaebens刚刚添加了它-虽然正如我所说,问题只发生在我从上载控制器分离时,但从其他控制器获取和加载图像时会非常完美,这就是为什么我认为问题一定在上载功能中。请尝试在上使用
.observeSingleEvent
e posts reference而不是
observe
,看看这是否改变了什么,反正你似乎是在删除侦听器。@PieterLaebens实际上修复了它-为什么这样做?
。observeSingleEvent
确保它只获取一次帖子?很抱歉,如果这是基本的,我是在遵循一个教程,它不是crystal cl听听幕后发生了什么。我会解释的。你能给我们看看fetchPosts()吗方法?请把它放在您的问题中。@PieterLaebens刚刚添加了它-虽然正如我所说,问题只发生在我从上载控制器分离时,但从其他控制器获取和加载图像时会非常完美,这就是为什么我认为问题一定在上载功能中。请尝试在上使用
.observeSingleEvent
e posts reference而不是
observe
,看看这是否改变了什么,反正你似乎是在删除侦听器。@PieterLaebens实际上修复了它-为什么这样做?
。observeSingleEvent
确保它只获取一次帖子?很抱歉,如果这是基本的,我是在遵循一个教程,它不是crystal cl听听幕后发生了什么。我会在回答中解释。非常感谢你的回答和解释!这听起来确实像是发生了什么,因为会有一段时间的延迟
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()
                }
            }
        }
    })
}