Я использую режим загрузки в основном в соответствии с этой темой:
Загрузка «оверлея» при выполнении длительных задач в iOS
Я использую один и тот же код в нескольких ViewController, поэтому создал расширение:
extension UIViewController {
func showLoading() {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: false, completion: nil)
}
func hideLoading() {
if ( presentedViewController != nil && !presentedViewController!.isBeingPresented ) {
dismiss(animated: false, completion: nil)
}
}
}
Обычно я использую такой код:
self.showLoading()
callNetwork() { response in
DispatchQueue.main.async {
self.hideLoading()
....
}
}
Если сетевой вызов занимает 0,5 с или более, все работает нормально. Проблема в том, что сеть слишком быстрая. Тогда я получу ошибку, похожую на эту:
Warning: Attempt to dismiss from view controller <UINavigationController: 0x7ff581830a00> while a presentation or dismiss is in progress!
И модальное окно не будет закрыто.
Лучшее решение, которое я могу придумать, - это что-то вроде этого (суперкласс вместо расширения, поскольку расширения не могут иметь переменных):
class LoadingViewController: UIViewController {
var shouldDismissImmediately = false
func showLoading() {
shouldDismissImmediately = false
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: false) {
if (self.shouldDismissImmediately) {
self.dismiss(animated: false, completion: nil)
}
}
}
func hideLoading() {
if ( presentedViewController != nil && !presentedViewController!.isBeingPresented ) {
dismiss(animated: false, completion: nil)
} else {
shouldDismissImmediately = true
}
}
}
Кто-нибудь может придумать лучшее решение? Это просто не кажется правильным. Может я что-то в корне не так делаю. Типа - должен ли я вообще показывать такой диалог при ожидании ответа сети? Есть ли лучший способ заставить пользователя ждать? Мне нужно, чтобы пользователь знал, что что-то происходит, и в то же время мне нужно, чтобы он не мог нажимать какие-либо кнопки в пользовательском интерфейсе.





extension UIViewController {
func showLoading(finished: @escaping () -> Void) {
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
present(alert, animated: false, completion: finished)
}
func hideLoading(finished: @escaping () -> Void) {
if ( presentedViewController != nil && !presentedViewController!.isBeingPresented ) {
dismiss(animated: false, completion: finished)
}
}
}
self.showLoading(finished: {
callNetwork() {
DispatchQueue.main.async {
self.hideLoading(finished: {
// done
})
}
}
})