正如其他人指出的,你想避免等待主线程,冒着死锁的风险。因此,尽管您可以将其推送到全局队列,但另一种方法是采用许多机制之一来执行一系列异步任务。选项包括异步Operation
子类或承诺(例如PromiseKit)。
例如,包裹图像中的异步Operation
节能任务,并将它们添加到OperationQueue
您可以定义您的影像保存操作,像这样:
class ImageSaveOperation: AsynchronousOperation {
let image: UIImage
let imageCompletionBlock: ((NSError?) -> Void)?
init(image: UIImage, imageCompletionBlock: ((NSError?) -> Void)? = nil) {
self.image = image
self.imageCompletionBlock = imageCompletionBlock
super.init()
}
override func main() {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
imageCompletionBlock?(error)
complete()
}
}
然后,假设你有一个数组,images
,即这是一个[UIImage]
,你可以再做:
let queue = OperationQueue()
queue.name = Bundle.main.bundleIdentifier! + ".imagesave"
queue.maxConcurrentOperationCount = 1
let operations = images.map {
return ImageSaveOperation(image: $0) { error in
if let error = error {
print(error.localizedDescription)
queue.cancelAllOperations()
}
}
}
let completion = BlockOperation {
print("all done")
}
operations.forEach { completion.addDependency($0) }
queue.addOperations(operations, waitUntilFinished: false)
OperationQueue.main.addOperation(completion)
可以很明显的自定义它在错误的重试添加逻辑,但是很可能现在还没有必要,因为“去根o忙“问题是由于太多的并发保存请求而导致的,我们已经取消了这些。这只留下不可能通过重试解决的错误,所以我可能不会添加重试逻辑。 (错误更可能是权限失败,空间不足等)但是如果您真的想要,可以添加重试逻辑。更有可能的是,如果你有错误,你可能只想取消队列上的所有剩余操作,就像我上面所说的那样。
请注意,上面的小类AsynchronousOperation
,这只是Operation
子类,isAsynchronous
返回true
。例如:
/// Asynchronous Operation base class
///
/// This class performs all of the necessary KVN of `isFinished` and
/// `isExecuting` for a concurrent `NSOperation` subclass. So, to developer
/// a concurrent NSOperation subclass, you instead subclass this class which:
///
/// - must override `main()` with the tasks that initiate the asynchronous task;
///
/// - must call `completeOperation()` function when the asynchronous task is done;
///
/// - optionally, periodically check `self.cancelled` status, performing any clean-up
/// necessary and then ensuring that `completeOperation()` is called; or
/// override `cancel` method, calling `super.cancel()` and then cleaning-up
/// and ensuring `completeOperation()` is called.
public class AsynchronousOperation : Operation {
private let syncQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".opsync")
override public var isAsynchronous: Bool { return true }
private var _executing: Bool = false
override private(set) public var isExecuting: Bool {
get {
return syncQueue.sync { _executing }
}
set {
willChangeValue(forKey: "isExecuting")
syncQueue.sync { _executing = newValue }
didChangeValue(forKey: "isExecuting")
}
}
private var _finished: Bool = false
override private(set) public var isFinished: Bool {
get {
return syncQueue.sync { _finished }
}
set {
willChangeValue(forKey: "isFinished")
syncQueue.sync { _finished = newValue }
didChangeValue(forKey: "isFinished")
}
}
/// Complete the operation
///
/// This will result in the appropriate KVN of isFinished and isExecuting
public func complete() {
if isExecuting { isExecuting = false }
if !isFinished { isFinished = true }
}
override public func start() {
if isCancelled {
isFinished = true
return
}
isExecuting = true
main()
}
}
现在,我很欣赏的操作队列(或承诺)是要看起来像矫枉过正您的具体情况,但它是你可以使用任何你有一系列的异步任务的有用的模式。有关操作队列的更多信息,请随时参阅Concurrency Programming Guide: Operation Queues。
来源
2017-07-14 21:30:31
Rob
你应该尝试把你的代码放在Dispatach.global队列中,它肯定会有帮助 –
@MikeAlter它确实有帮助。它现在有效,但我不知道为什么,你能帮忙解释一下吗?谢谢 – user339946