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
}
}
}
谁能想到更好的解决方案?就是这个感觉不太对。也许我在做一些根本错误的事情。就像 - 在等待网络响应时,我什至应该呈现这样的对话框吗?有没有更好的方法让用户等待?我需要用户意识到正在发生某些事情,同时我需要他不能按下 UI 中的任何按钮。
解决方案
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
})
}
}
})
推荐阅读
- netlogo - 在 netlogo 中设置海龟坐标以修补颜色
- xml - XML 架构未验证
- java - Bouncycastle 签名数据消息中的附加八位字节字符串
- ruby-on-rails - 当数组不包含预期的数据类型时引发错误
- java - C# 中的 Java AES/CBC/PKCS5Padding
- mathcad - Mathcad 错误:“他的数组索引对此数组无效”
- node.js - 更新 CloudFunctions 上的子集合
- python - 对所有节点中每条最短路径的权重求和
- node.js - 为什么 preload.js 返回“错误:找不到模块”?
- node.js - 写特性——Nodejs、Bleno、蓝牙