我有一个集合视图,显示从我的一个视图控制器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()
}
}
}
})
}
答案 0 :(得分:3)
当您使用removeAllObservers
时,它会继续监控更改。您之后使用.observeSingleEvent
因此我假设您只需要一次数据。在这种情况下,最好使用.value
,因为这只会获取一次数据。
这就是我认为正在发生的事情,如果没有看到代码执行就很难分辨。由于Firebase是异步的,因此代码会继续执行,并且不会等待Firebase命令完成。我认为在updateChildValues实际完成之前,您正在使用Feed。到达FeedViewController后,您清空了集合并加载了数据。数据将开始加载,在加载时,将添加帖子。这再次触发.observe
,因为数据库中发生了某些变化,导致它多次运行。由于您只在viewDidLoad中清除了您的收藏集,因此重复的帖子会附加到您的收藏中。
要避免这种情况,请将observeSingleEvent
替换为removeAll()
,或者不要使用viewDidLoad
中的.observe
,而是在{{1}}内使用{{1}}我认为必须在主队列上这样做。