我所做的 - 只是允许Operation
并URLSessionTask
保持分开。为此,我进行了通用异步块操作,用于实例化、恢复、取消URLSessionTask
。
因此,在 ViewController 或 Data 层中,我仍在使用 chained Operations
with URLSessionTasks
inside。下面的示例代码可以通过子类化来扩展AsynchronousBlockOperation
。
文件 1. 通用异步操作。
open class AsynchronousOperation: Operation {
private var lockOfProperties = NonRecursiveLock.makeDefaultLock()
private var mFinished = false
private var mExecuting = false
public override init() {
super.init()
}
/// Subclasses must launch job here.
///
/// **Note** called between willChangeValueForKey and didChangeValueForKey calls, but after property mExecuting is set.
open func onStart() {
}
/// Subclasses must cancel job here.
///
/// **Note** called immediately after calling super.cancel().
open func onCancel() {
}
/// Subclasses must release job here.
///
/// **Note** called between willChangeValueForKey and didChangeValueForKey calls,
/// but after properties mExecuting and mFinished are set.
open func onFinish() {
}
}
extension AsynchronousOperation {
public final override var isAsynchronous: Bool {
return true
}
public final override var isExecuting: Bool {
return lockOfProperties.synchronized { mExecuting }
}
public final override var isFinished: Bool {
return lockOfProperties.synchronized { mFinished }
}
}
extension AsynchronousOperation {
public final override func start() {
if isCancelled || isFinished || isExecuting {
return
}
willChangeValue(forKey: #keyPath(Operation.isExecuting))
lockOfProperties.synchronized { mExecuting = true }
onStart()
didChangeValue(forKey: #keyPath(Operation.isExecuting))
}
public final override func cancel() {
super.cancel()
if isExecuting {
onCancel()
finish()
} else {
onCancel()
lockOfProperties.synchronized {
mExecuting = false
mFinished = true
}
}
}
public final func finish() {
willChangeValue(forKey: #keyPath(Operation.isExecuting))
willChangeValue(forKey: #keyPath(Operation.isFinished))
lockOfProperties.synchronized {
mExecuting = false
mFinished = true
}
onFinish()
didChangeValue(forKey: #keyPath(Operation.isExecuting))
didChangeValue(forKey: #keyPath(Operation.isFinished))
}
}
文件 2. 基于异步块的操作:
open class AsynchronousBlockOperation: AsynchronousOperation {
public typealias WorkItemType = OperationCancelationType & OperationResumingType
public typealias FinaliseBlock = () -> Void
public typealias WorkItemBlock = (@escaping FinaliseBlock) -> WorkItemType?
private var executionBlock: WorkItemBlock
private var blockExecutionQueue: DispatchQueue?
private var workItemToken: WorkItemType?
public init(blockExecutionQueue: DispatchQueue? = nil, executionBlock: @escaping WorkItemBlock) {
self.blockExecutionQueue = blockExecutionQueue
self.executionBlock = executionBlock
super.init()
}
open override func onStart() {
if let queue = blockExecutionQueue {
queue.async {
self.execute()
}
} else {
execute()
}
}
open override func onCancel() {
workItemToken?.cancelOperation()
}
private func execute() {
workItemToken = executionBlock { [weak self] in
self?.finish()
}
if var token = workItemToken {
token.resumeOperation()
} else {
finish()
}
}
}
文件 3. 协议
public protocol OperationCancelationType {
mutating func cancelOperation()
}
public protocol OperationResumingType {
mutating func resumeOperation()
}
extension URLSessionTask: OperationCancelationType {
public func cancelOperation() {
cancel()
}
}
extension URLSessionTask: OperationResumingType {
public func resumeOperation() {
resume()
}
}
用法:
let operation = AsynchronousBlockOperation { [weak self] finalise in
return session.dataTask(with: url) {
...
finalise() // This will finish operation
}
}