Вложенные обработчики завершения, которые не возвращают элементы для отправки в TableViewController

#swift #xcode #completionhandler

#swift #xcode #обработчик завершения

Вопрос:

Я хочу получить некоторые данные из firebaseFirestore и загрузить URL-адрес изображения из firebaseStorage во время подготовки к моему переходу, который приведет пользователя к TableViewController, где они будут отображаться. Даже при использовании некоторых вложенных обработчиков завершения (возможно, я сделал код слишком длинным), я все еще не могу выполнять свои асинхронные задачи по порядку, таким образом, слишком рано переходя к переходу. Для простоты я использую единый переход (без идентификаторов). В ViewControllerForTable я указал переменную var cells : [Cella] = [] глобально.

 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)
        })

    }
}
  

Комментарии:

1. в какой момент вы вызываете performSegue ? Я не уверен, правильно ли я понял ваш вопрос или код. Есть ли еще код, которым вы можете поделиться?

2. @NitinAlabur Кнопка, которая запускает переход, подключена к следующему VC, потому что они встроены в тот же навигационный контроллер. Я поделюсь дополнительной частью кода, как только вернусь домой.

3. ОК. Итак, ваш текущий поток — [Tap Button] -> [Выполняет переход] -> [Загрузить из firebase], и ваша проблема в том, что анимация перехода происходит до вызова завершения firebase. Верно?

Ответ №1:

Если я правильно понял ваш вопрос, вот что вам нужно сделать:

Отключите переход для кнопки в вашей раскадровке.

В функции IBAction для кнопки выполните свою prepareDataForSegue работу

После вызова обработчика завершения вызовите performSegue , который вызовет prepareSegue , где вы можете назначить загруженный cella.

Это должно загружать tableVC только тогда, когда данные доступны.