swift - 在 VC1 中从 firebase 检索用户数据并将其发送到 VC2 中的 TableView 以显示时出现问题

标签 swift firebase google-cloud-firestore tableview

我在从 firebase firestore 检索所有数据时遇到问题(它跟踪一些用户信息,即标题、描述和 imageURL),然后从 firebaseStorage 下载图像,创建一个名为 Cella(title: String, description:字符串,图像:UIImage)。这个过程应该在一个循环中发生,然后为每个用户创建一个对象,并返回一个 Cella 对象数组以传递给另一个 ViewController 并显示在它的 tableView 上。

我尝试修复完成处理程序,因为我认为它们是问题所在,然后我添加了一个 IBAction,它在执行 segue 时被触发。

我尝试检索数据的 ViewController(请注意,它位于导航 View Controller 内,并且 segue 是唯一的一个,当按下该按钮时会触发它)。

class ViewController: UIViewController {

let firestoreUsersReference = Firestore.firestore().collection("users")
let storageReference = Storage.storage()

var cellaObjects : [Cella] = []


override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    getDocumentsFromFirestore(firestoreReference: firestoreUsersReference) { (cellaArray) in
        self.cellaObjects = cellaArray
    }

}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

}

func getImagesDownloaded(reference: StorageReference, completion: @escaping (UIImage?,Error?)->()) {
    reference.getData(maxSize: 10*1024*1024) { (data, error) in
        guard error == nil, let data = data else {
            completion(nil,error)
            return
        }
        guard let image = UIImage(data: data) else {
            completion(nil, FirebaseErrors.expectedImage)
            return
        }
        completion(image,nil)
    }
}
enum FirebaseErrors: Error {
    case expectedImage
}


func getDocumentsFromFirestore (firestoreReference: CollectionReference, completion: @escaping ([Cella])->()) {


    var cellaArray : [Cella] = []

    firestoreUsersReference.getDocuments { (querySnapshot, err) in
        if err != nil {
            print("There has been an error \(String(describing: err?.localizedDescription))")
        }
        else {

            for documents in querySnapshot!.documents {
                print("\(documents.documentID) => \(documents.data())")
                let data = documents.data()
                let title = data["userTitle"] as! String
                let description = data["userDescription"] as! String
                let imageURL = data["userImageURL"] as! String
                print("Title: \(String(describing: title)), Description: \(String(describing: description)), imageURL: \(imageURL)")

                self.cellCreationProcess(title: title, description: description, imageURL: imageURL, completion: { (newCell) in
                    cellaArray.append(newCell)
                })


                }
            completion(cellaArray)
            }

        }
    }

func cellCreationProcess(title: String, description: String, imageURL: String, completion: @escaping (Cella) -> ()) {

    let storagePath = Storage.storage().reference(forURL: imageURL)

    self.getImagesDownloaded(reference: storagePath, completion: { (image, error) in
        guard let image = image, error == nil else {
            print(String(describing : error?.localizedDescription))
            return
        }
        print("TITLE: \(String(describing: title)), IMAGE: \(image)")
        let newCell = Cella(image: image, title: title, bodyMessage: description)
        completion(newCell)
    })

}

}

TableView所在的ViewController:

class ViewControllerForTable: UIViewController, UITableViewDataSource, UITableViewDelegate {

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let currentCell = tableView.cellForRow(at: indexPath) as! TableViewCell

    let information = Information(title: currentCell.title.text!, description: currentCell.bodyText.text!, sellerImage: currentCell.CellImage.image!)

    let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerDisplay") as! ViewControllerDisplay

    destinationVC.dataPassed = information

    self.navigationController?.pushViewController(destinationVC, animated: true)
}


@IBOutlet weak var UITableView: UITableView!


let image : UIImage = UIImage(named: "image1")!

var cells : [Cella] = []

override func viewDidLoad() {
    super.viewDidLoad()

    //states that this class is the delegate of the data and the object tableView within this VC
    UITableView.delegate = self
    UITableView.dataSource = self

    //force sets each of the the tableView rows to have a height of 200
    UITableView.rowHeight = 200

    // Do any additional setup after loading the view.
}

//Function hardcoded that creates the 5 cells to test the app

//MARK - Table view settings

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //meaning my UITableView is going to have cells.count different rows
    return cells.count

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    //Gets each item singularly in order from the dictionary of cells
    let cellFormat = cells[indexPath.row]

    //You need to do this Nib thing because you created a xib file

    let nib = UINib(nibName: String(describing: TableViewCell.self), bundle: nil)

    tableView.register(nib, forCellReuseIdentifier: "customCell")

    // Says that it is going to create a reusable cell with the identifier from the XIB file and it is going to use the class TableViewCell to access its properties
    let cellObject = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! TableViewCell

    //Creates and assigns the values from the item in the dictionary to the CellFormat for them to be displayed in the custom cell

    cellObject.setCell(cellFormatTaken: cellFormat)

    // returns the final Cell Item

    return cellObject

}

@IBAction func unwindToActivitieslList(sender: UIStoryboardSegue) {
    let sourceViewController = sender.source as? ViewController
    let activities = sourceViewController?.cellaObjects
    cells = activities!
    UITableView.reloadData()
}
}

----------------更新---------------- 我已经删除了

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    getDocumentsFromFirestore(firestoreReference: firestoreUsersReference) { (cellaArray) in
        self.cellaObjects = cellaArray
    }

}

并添加了按钮 @IBAction func sardiniaNePressed(_ sender: UIButton) {

    getDocumentsFromFirestore(firestoreReference: firestoreUsersReference) { (cellaArray) in
        self.cellaObjects = cellaArray
        self.performSegue(withIdentifier:"sardiniaNe",sender:nil)
    }
}

我还按照善意的建议添加了 dispatch。尽管如此,我仍然无法获取要显示的数据。按钮的另一个问题是,每当我单击它时,由于 VC 嵌入在导航 Controller 中,它们会创建目标 ViewController 的“副本”,并且在应用程序打开的整个过程中一直这样做,留给我许多重复项,空行。

最佳答案

您需要在 prepare(for segue: 之外调用此方法(直接在按钮操作中)并在完成时执行 segue

getDocumentsFromFirestore(firestoreReference: firestoreUsersReference) { (cellaArray) in
    self.cellaObjects = cellaArray
    self.performSegue(withIdentifier:"segue",sender:nil)
}

此外,您还需要 DispatchGroup(),因为获取每个项目的图像是异步的

func getDocumentsFromFirestore (firestoreReference: CollectionReference, completion: @escaping ([Cella])->()) {


    var cellaArray : [Cella] = []

    firestoreUsersReference.getDocuments { (querySnapshot, err) in
        if err != nil {
            print("There has been an error \(String(describing: err?.localizedDescription))")
        }
        else {

            let g = DispatchGroup()

            for documents in querySnapshot!.documents {

                g.enter()
                print("\(documents.documentID) => \(documents.data())")
                let data = documents.data()
                let title = data["userTitle"] as! String
                let description = data["userDescription"] as! String
                let imageURL = data["userImageURL"] as! String
                print("Title: \(String(describing: title)), Description: \(String(describing: description)), imageURL: \(imageURL)")

                self.cellCreationProcess(title: title, description: description, imageURL: imageURL, completion: { (newCell) in
                    cellaArray.append(newCell)
                    g.leave()
                })


            }

            g.notify(queue: .main, execute: {
                 completion(cellaArray)
            })

        }

    }
}

关于swift - 在 VC1 中从 firebase 检索用户数据并将其发送到 VC2 中的 TableView 以显示时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55591442/

相关文章:

ios - Swift 错误,UIMenuItem 到 UIview/UIlabel 进行复制

firebase - 数组的元素是固定长度的,而数组本身不是

rest - 如何使用 REST 在 Firestore 文档中插入服务器时间戳?

firebase - 无法使用Flutter和Firebase将数据写入Firestore

ios - 在太空入侵者中生成 Sprite

ios - UITableViewCell带有自调整大小标签的扩展动画,视觉动画问题

swift - 是否可以在 Swift 中缩写此条件?

android - 无法解析 : firebase-auth-15. 0.0

javascript - 页面没有在 Angularjs 中重定向

android - 当 Android 中数组中的值超过 1 个时,Firestore whereArrayContains 不起作用