简体   繁体   中英

Nested completion handlers that do not return items to be sent to TableViewController

I want to get some data from firebaseFirestore and download an image URL from firebaseStorage, while preparing for my segue that will bring the user to the TableViewController, where they will be displayed. Even when using some nested completion handlers (perhaps I made the code too longs), I'm still not able to perform my asyncronous tasks in order, thus rushing too early to the segue. For simplicity I'm using the single segue (no identifiers). In the ViewControllerForTable I have stated a variable var cells : [Cella] = [] globally.

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



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

    let destinationVC = segue.destination as! ViewControllerForTable

    prepareDataForSegue(firestoreReference: firestoreUsersReference) { (cella) in
        destinationVC.cells = cella
        print(destinationVC.cells)
    }
}



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 prepareDataForSegue (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 {
            self.getDocumentsFromFirestore(querySnapshot: querySnapshot, completion: { (title, description, image) in
                let newCell = Cella(image: image, title: title, bodyMessage: description)
                print("NEW CELL : \(newCell)")
                cellaArray.append(newCell)
            })
        }
    }
    completion(cellaArray)
}


func getDocumentsFromFirestore (querySnapshot: QuerySnapshot?, completion: @escaping (String,String,UIImage)->()) {
    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)")
        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)")
            completion(title!, description!, image)
        })

    }
}

If I understand your question correctly, here what you need to do:

Disconnect the segue for the button in your storyboard.

In the IBAction function for the button, do your prepareDataForSegue work

Once the completion handler is called, call performSegue , which will call the prepareSegue , where you can assign the downloaded cella.

This should load the tableVC only when the data is available.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM