#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 только тогда, когда данные доступны.