UIActivityIndicator 需要几秒钟才能被关闭
UIActivityIndicator taking several seconds to be dismissed
我有一些代码使用 OperationQueue
做一些后台工作,所以我使用 UIAlertController
来管理微调器,同时操作 运行。
问题是在调用 dismiss()
之后,微调器在屏幕上显示了很长时间。
下面我展示了我 运行ning 的代码,以及当我 运行 模拟器中的代码时得到的输出。
这个函数在ViewController
:
@IBAction func runTheTest(_ sender: Any) {
// MARK: Define web interaction parameters
let config = URLSessionConfiguration.default
config.waitsForConnectivity = true
let defaultSession = URLSession(configuration: config)
let url = URL(string: "https://www.google.com")
var getUrlRequest = URLRequest(url: url!)
getUrlRequest.httpMethod = "GET"
// MARK: operations CREATION
let getFormOp = GetFormOperation(getRequest: getUrlRequest, defaultSession: defaultSession, credentials: ["test":"test"], viewController: self)
let finishOp = FinishOperation(viewController: self)
// MARK: operations SET DEPENDENCIES
finishOp.addDependency(getFormOp) // finish op is dependent on get op finishing
getFormOp.defineFollowOnOperation(finishOp) // This would be if we needed to share data between the two
// MARK: start the SPINNER
LoaderController.sharedInstance.showLoader(viewController: self, title: "Please Wait...", message: "Getting data from the web")
// MARK: initiate the long-running set of operations
let operationQueue = OperationQueue()
operationQueue.addOperations([getFormOp, finishOp], waitUntilFinished: false)
print("operations are running")
}
这是管理 activity 指标的 class:
class LoaderController: NSObject {
static let sharedInstance = LoaderController()
private let activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
private var start = DispatchTime.now()
func showLoader(viewController: ViewController, title: String, message: String) {
start = DispatchTime.now()
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = .gray
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
self.activityIndicator.startAnimating()
alert.view.addSubview(activityIndicator)
viewController.present(alert, animated: true, completion: nil)
print("load indicator presented")
}
func removeLoader(viewController: ViewController){
let removeCalled = DispatchTime.now()
let spinnerSeconds = (removeCalled.uptimeNanoseconds - start.uptimeNanoseconds) / 1000000000
print("load indicator remove request after \(spinnerSeconds) seconds.")
viewController.dismiss(animated: true, completion: {
let finallyGone = DispatchTime.now()
let spinnerSeconds = (finallyGone.uptimeNanoseconds - removeCalled.uptimeNanoseconds) / 1000000000
print("load indicator gone after \(spinnerSeconds) additional seconds.")
})
}
}
输出如下所示:
load indicator presented
operations are running
load indicator remove request after 6 seconds.
load indicator gone after 4 additional seconds.
我在模拟器中观察到的与打印语句一致;操作完成,但微调器会再保持 4 秒。
我在这里做错了什么,我该如何解决?
如果这个问题缺少您认为必要的任何属性,我会致力于改进它,或者如果合适的话,我会删除这个问题,所以请使用评论告诉我。
removeLoader
,与所有 UI 操作一样,只能从主线程调用。如果您从 Operation
(而不是 OperationQueue.main
)调用该方法,它应该如下所示:
DispatchQueue.main.async {
viewController.removeLoader(...)
}
这种延迟几乎总是暗示您正在从后台队列执行 UI 操作。
在模拟器上调试时打开Main Thread Checker也是个好主意。
它会帮助你。试试这个
DispatchQueue.main.async {
viewController.removeLoader()
//call your removeLoader method inside the asynchronous queue
}
我有一些代码使用 OperationQueue
做一些后台工作,所以我使用 UIAlertController
来管理微调器,同时操作 运行。
问题是在调用 dismiss()
之后,微调器在屏幕上显示了很长时间。
下面我展示了我 运行ning 的代码,以及当我 运行 模拟器中的代码时得到的输出。
这个函数在ViewController
:
@IBAction func runTheTest(_ sender: Any) {
// MARK: Define web interaction parameters
let config = URLSessionConfiguration.default
config.waitsForConnectivity = true
let defaultSession = URLSession(configuration: config)
let url = URL(string: "https://www.google.com")
var getUrlRequest = URLRequest(url: url!)
getUrlRequest.httpMethod = "GET"
// MARK: operations CREATION
let getFormOp = GetFormOperation(getRequest: getUrlRequest, defaultSession: defaultSession, credentials: ["test":"test"], viewController: self)
let finishOp = FinishOperation(viewController: self)
// MARK: operations SET DEPENDENCIES
finishOp.addDependency(getFormOp) // finish op is dependent on get op finishing
getFormOp.defineFollowOnOperation(finishOp) // This would be if we needed to share data between the two
// MARK: start the SPINNER
LoaderController.sharedInstance.showLoader(viewController: self, title: "Please Wait...", message: "Getting data from the web")
// MARK: initiate the long-running set of operations
let operationQueue = OperationQueue()
operationQueue.addOperations([getFormOp, finishOp], waitUntilFinished: false)
print("operations are running")
}
这是管理 activity 指标的 class:
class LoaderController: NSObject {
static let sharedInstance = LoaderController()
private let activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
private var start = DispatchTime.now()
func showLoader(viewController: ViewController, title: String, message: String) {
start = DispatchTime.now()
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = .gray
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
self.activityIndicator.startAnimating()
alert.view.addSubview(activityIndicator)
viewController.present(alert, animated: true, completion: nil)
print("load indicator presented")
}
func removeLoader(viewController: ViewController){
let removeCalled = DispatchTime.now()
let spinnerSeconds = (removeCalled.uptimeNanoseconds - start.uptimeNanoseconds) / 1000000000
print("load indicator remove request after \(spinnerSeconds) seconds.")
viewController.dismiss(animated: true, completion: {
let finallyGone = DispatchTime.now()
let spinnerSeconds = (finallyGone.uptimeNanoseconds - removeCalled.uptimeNanoseconds) / 1000000000
print("load indicator gone after \(spinnerSeconds) additional seconds.")
})
}
}
输出如下所示:
load indicator presented
operations are running
load indicator remove request after 6 seconds.
load indicator gone after 4 additional seconds.
我在模拟器中观察到的与打印语句一致;操作完成,但微调器会再保持 4 秒。
我在这里做错了什么,我该如何解决?
如果这个问题缺少您认为必要的任何属性,我会致力于改进它,或者如果合适的话,我会删除这个问题,所以请使用评论告诉我。
removeLoader
,与所有 UI 操作一样,只能从主线程调用。如果您从 Operation
(而不是 OperationQueue.main
)调用该方法,它应该如下所示:
DispatchQueue.main.async {
viewController.removeLoader(...)
}
这种延迟几乎总是暗示您正在从后台队列执行 UI 操作。
在模拟器上调试时打开Main Thread Checker也是个好主意。
它会帮助你。试试这个
DispatchQueue.main.async {
viewController.removeLoader()
//call your removeLoader method inside the asynchronous queue
}