观察到来自 Firebase 的调用在函数退出后未更新字典的值



我正在尝试学习iOS编程,所以我认为模仿Instagram提要是个好主意。每个人都使用这个基本提要,我想知道该怎么做。

基本思想是将一个图像/文本帖子显示在单个列中。现在我有一个图像要显示。

我目前正在从火库中正确提取图片网址。唯一的问题是我的收藏视图仍然显示为空。我几个月前开始了这个项目,我忘记了教程在哪里。请帮我填空。这是代码:

import UIKit
import SwiftUI
import Firebase
import FirebaseUI
import SwiftKeychainWrapper
class FeedViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{

@IBOutlet weak var collectionview: UICollectionView!
//var posts = [Post]()

var posts = [String](){
didSet{
collectionview.reloadData()
}
}
var following = [String]()
var posts1 = [String]()
var userStorage: StorageReference!
var ref : DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
posts1 = fetchPosts()
//let myIndexPath = IndexPath(row: 0, section: 0)
//collectionView(collectionview, cellForItemAt: myIndexPath)
//print(self.posts1.count)
}
func  fetchPosts() -> [String]{
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("posts")
let uids = Database.database().reference().child("users")
uids.observe(DataEventType.value, with: { (snapshot) in
let dict = snapshot.value as! [String:NSDictionary]
for (_,value) in dict {
if let uid = value["uid"] as? String{
self.following.append(uid)
}
}
ref.observe(DataEventType.value, with: { (snapshot2) in
let dict2 = snapshot2.value as! [String:NSDictionary]
for(key, value) in dict{
for uid2 in self.following{
if (uid2 == key){
for (key2,value2) in value as! [String:String]{
//print(key2 + "this is key2")
if(key2 == "urlToImage"){
let urlimage = value2
//print(urlimage)
self.posts1.append(urlimage)
self.collectionview.reloadData()
print(self.posts1.count)
}
}
}
}
}
})
})
//ref.removeAllObservers()
//uids.removeAllObservers()
print("before return")
print(self.posts1.count)
return self.posts1
override func viewDidLayoutSubviews() {
collectionview.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) ->Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts1.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PostCell", for: indexPath) as! PostCell
cell.postImage.sd_setImage(with: URL(string: posts1[indexPath.row]))
//creating the cell
//cell.postImage.downloadImage(from: self.posts[indexPath.row])
//        let storageRef = Storage.storage().reference(forURL: self.posts[indexPath.row].pathToImage)
//
//
print("im trying")
//let stickitinme = URL(fileURLWithPath: posts1[0])
//cell.postImage.sd_setImage(with: stickitinme)
//cell.authorLabel.text = self.posts[indexPath.row].author
//cell.likeLabel.text = "(self.posts[indexPath.row].likes) Likes"
return cell
}

@IBAction func signOutPressed(_sender: Any){
signOut()
self.performSegue(withIdentifier: "toSignIn", sender: nil)
}
@objc func signOut(){
KeychainWrapper.standard.removeObject(forKey:"uid")
do{
try Auth.auth().signOut()
} catch let signOutError as NSError{
print("Error signing out: %@", signOutError)
}
dismiss(animated: true, completion: nil)
}

/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

更新

观察调用不会更新帖子(字典(的值。观察呼叫退出后,帖子的值将设置回空。

PostCell类,如要求:

import UIKit
class PostCell: UICollectionViewCell {

@IBOutlet weak var postImage: UIImageView!
@IBOutlet weak var authorLabel: UILabel!
@IBOutlet weak var likeLabel:UILabel!
@IBOutlet weak var likeBtn:UIButton!
@IBOutlet weak var unlikeBtn:UIButton!
@IBAction func likePressed (_ sender: Any){
}
@IBAction func unlikePressed(_sender: Any){
}
}

我认为问题是: 您的集合视图数据源仅被调用一次。由于图像 url 加载是异步的,因此每次将新数据追加到数据源数组时,都需要刷新集合视图,如下所示:

self.posts.append(urlimage)
collectionView.reloadData()

或:

var posts = [UIImage](){
didSet{
collectionView.reloadData()
}
}

希望这有帮助。

编辑更新: 关于异步调用,我认为您应该使用转义闭包,一旦网络请求收到响应,它就会运行代码块。

首先分离网络调用函数,如下所示:

func fetchUsers(completion: @escaping(_ dictionary: [String: NSDictionary])->()){
let uid = Auth.auth().currentUser!.uid
let uids = Database.database().reference().child("users")
uids.observe(DataEventType.value, with: { (snapshot) in
let dict = snapshot.value as! [String:NSDictionary]
completion(dict)
})
}
func fetchURLS(completion: @escaping(_ dictionary: [String: String])->()){
let ref = Database.database().reference().child("posts")
ref.observe(DataEventType.value, with: { (snapshot2) in
let dict2 = snapshot2.value as! [String:String]
completionTwo(dict2)
})
}

然后,解析函数:

func parseUsers(dictionary: [String: NSDictionary]){
for (_,value) in dictionary {
if let uid = value["uid"] as? String{
self.following.append(uid)
}
}
fetchURLS { (urlDictionary) in
self.parseImageURLS(dictionary: urlDictionary)
}
}
func parseImageURLS(dictionary: [String: String]){
for(key, value) in dictionary{
for uid2 in self.following{
if (uid2 == key){
for (key2,value2) in value as! [String:String]{
//print(key2 + "this is key2")
if(key2 == "urlToImage"){
let urlimage = value2
//print(urlimage)
self.posts1.append(urlimage)
self.collectionview.reloadData()
print(self.posts1.count)
}
}
}
}
}
}

然后添加:

fetchUsers { (usersDictionary) in
self.parseUsers(dictionary: usersDictionary)
}

viewDidLoad()

希望这能解决您的问题。附带说明:我建议使用模型并将网络调用分隔在不同的文件中。随时提出任何问题。

经过更多搜索,我想出了该怎么做。

我错误地假设 CollectionView 是在 viewDidLoad(( 函数完成后加载的。CollectionView 的帮助程序类被调用以调用 reloadData。

我观察到我的重新加载数据调用没有被调用。为了完成这项工作,我在 viewDidLoad 函数中添加了 2 行代码:

collectionview.delegate = self
collectionview.dataSource = self

通过此更改,现在将加载图像。

最新更新