Фон:
Я использую библиотеку под названием KolodaView
, которая генерирует карты в стиле Tinder для приложений Swift. Карты отображаются во время функции viewDidLoad()
моего контроллера представления после назначения делегата. Я написал функцию делегата viewForCardAt()
, чтобы для каждой отображаемой карты выполнялся вызов getPics()
, который устанавливает глобальную переменную imageResult: UIImageView
, содержащую UIImageView
(Примечание: UIView
, возвращаемое из viewForCardAt()
- это фактическое UIView
, которое будет помещено на карту).
Проблема:
getPics()
вызывает вызов базы (storageRef.getData()
) и, как следствие, асинхронный. Поскольку viewForCardAt()
должен что-то возвращать (в процессе генерации карточек) и выполняется в основном потоке, он не может ждать или получать «уведомление», когда функция getPics()
завершается. Невозможность ожидания приводит к тому, что визуализированные карты не имеют изображения, поскольку getPics()
не завершил выборку данных до того, как viewForCardAt()
вернет свои UIView
.
Что я пробовал:
Использование ожидания группы отправки, но поскольку оба этих вызова происходят в основном потоке, добавление оператора ожидания либо в функции Koloda viewForCardAt()
, либо даже в функции getPics()
приводит к зависанию всего приложения. Я думал о том, чтобы каким-то образом поместить getPics
в другой асинхронный поток, но тогда viewForCardAt()
все равно придется ждать завершения getPics()
, поскольку он не может вернуться, пока getPics()
не «вернет свое значение» (присвоит его значение к глобальной ссылке).
Соответствующий код (абстрагированный)
myViewController() {
var imageResult: UIImageView
override func viewDidLoad() {
self.kolodaView.delegate = self
}
.
.
.
func getPics() {
grabImageDispatchGroup.enter()
let storage = Storage.storage
let storageRef = storage.reference(forURL: photoLink)
//the asynch firebase call
storageRef.getData(....) { (data, error) in
//the actual result of the query being stored
//for the Koloda card to use on the current card
self.imageResult.image = UIImage(data: data)
grabImageDispatchGroup.leave()
}
}
//run for element in a specified 'user' array ("dataSource" stuff not shown for brevity)
func Koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
var cardView = UIView()
getPics()
grabImageDispatchGroup.notify() { //this cannot work since we must return a value
cardView.addSubview(imageResult)
return cardView
}
//invalid: 'this function must return something'
}
}