他の人が指摘しているように、デッドロックを招く危険性があるため、メインスレッドで待機することは避けたいと考えています。したがって、グローバルキューにプッシュすることができますが、もう1つの方法は、一連の非同期タスクを実行するための多くのメカニズムの1つを採用することです。オプションには、非同期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 busy "の問題は、あまりにも多くの並行保存要求の結果であり、私たちはこれを排除しました。再試行では解決されないエラーが残っているだけなので、リトライロジックは追加しないことにします。 (エラーは、パーミッションの失敗、スペース不足などの可能性が高いですが)本当に必要ならば、再試行ロジックを追加することができます。おそらく、エラーが発生した場合は、上記のように、キュー上の残りの操作をすべてキャンセルするだけです。
上記のサブクラス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