我不知道如何处理这种情况,因为我是iOS开发和Swift的新手。我正在执行数据提取:
func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!)
{
loadShows()
completionHandler(UIBackgroundFetchResult.NewData)
println("Background Fetch Complete")
}
我的loadShows()函数解析从加载到UIWebView的网站获取的一堆数据。问题是我有一个在loadShows函数中等待10秒左右的计时器。这允许在我开始解析数据之前完全加载页面中的javascript。我的问题是完成处理程序在我的loadShows()之前完成。
我想要做的是为“isCompletedParsingShows”添加一个bool,并使completionHandler行等待完成,直到该bool为真。处理这个问题的最佳方法是什么?
答案 0 :(得分:33)
你必须将你的异步函数传递给稍后调用的处理程序:
func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
loadShows(completionHandler)
}
func loadShows(completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
//....
//DO IT
//....
completionHandler(UIBackgroundFetchResult.NewData)
println("Background Fetch Complete")
}
添加一个中间completionHandler
func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) {
loadShows() {
completionHandler(UIBackgroundFetchResult.NewData)
println("Background Fetch Complete")
}
}
func loadShows(completionHandler: (() -> Void)!) {
//....
//DO IT
//....
completionHandler()
}
答案 1 :(得分:2)
解决这个问题的两种方法,都使用Grand Central Dispatch(在Swift和Objective C中类似):
更改 loadShows 方法以使其同步并使用与 completionHandler 相同的调度队列,然后将该方法的整个主体包装在 dispatch_async中;这样方法调用立即结束,但是如果完成了loadShows之后将调用completionHandler,就像在同步程序中一样
使用GCD信号量 - 就像你提到的BOOL一样,但是用 dispatch_semaphore_create 创建;在 completionHandler 之前调用 dispatch_semaphore_wait 使其等待解锁信号量(用 dispatch_semaphore_signal 解锁);请记住将方法体放在 dispatch_async 调用中,以免在等待loadShows完成时阻止其他应用程序。
答案 2 :(得分:0)
xCode 9.2,Swift 4
class AsyncOperation {
private let semaphore: DispatchSemaphore
private let dispatchQueue: DispatchQueue
typealias CompleteClosure = ()->()
init(numberOfSimultaneousActions: Int, dispatchQueueLabel: String) {
semaphore = DispatchSemaphore(value: numberOfSimultaneousActions)
dispatchQueue = DispatchQueue(label: dispatchQueueLabel)
}
func run(closure: @escaping (@escaping CompleteClosure)->()) {
dispatchQueue.async {
self.semaphore.wait()
closure {
self.semaphore.signal()
}
}
}
}
let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 1, dispatchQueueLabel: "AnyString")
asyncOperation.run { completeClosure in
// sync/async action
// ...
// action complete
completeClosure()
}
import UIKit
class ViewController: UIViewController {
let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 1, dispatchQueueLabel: "AnyString")
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 50, y: 50, width: 100, height: 40))
button.setTitle("Button", for: .normal)
button.setTitleColor(.blue, for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
view.addSubview(button)
}
@objc func buttonTapped() {
print("Button tapped at: \(Date())")
asyncOperation.run { completeClosure in
let counter = self.counter
print(" - Action \(counter) strat at \(Date())")
self.counter += 1
DispatchQueue.global(qos: .background).async {
sleep(1)
print(" - Action \(counter) end at \(Date())")
completeClosure()
}
}
}
}
http://iasecontent.disa.mil/stigs/zip/U_PostgreSQL_9-x_V1R1_STIG.zi