Ios 从一次调用中提取两次Firebase数据
我有一个集合视图,在其中一个视图控制器中显示从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,在用户选择要上传的图像后调用,它以某种方式导致图像被提取
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的任何逻辑位置。有人能看到我缺少的东西吗
编辑:MyfetchPosts()
函数:
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()
}
}
}
})
}