, markAsCompleted isFinished isExecuting. markAsCompleted isExecuting true. , , , isFinished .
:
- , isFinished isFinished.
, cancel , . :
class FiveSecondOperation: AsynchronousOperation {
var block: DispatchWorkItem?
override func main() {
block = DispatchWorkItem { [weak self] in
self?.finish()
self?.block = nil
}
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: block!)
}
override func cancel() {
super.cancel()
if isExecuting {
block?.cancel()
finish()
}
}
}
cancel, , DispatchWorkItem , , cancel .
, - , , cancel , super. :
class GetOperation: AsynchronousOperation {
var url: URL
weak var task: URLSessionTask?
init(url: URL) {
self.url = url
super.init()
}
override func main() {
let task = URLSession.shared.dataTask(with: url) { data, _, error in
defer { self.finish() }
}
task.resume()
self.task = task
}
override func cancel() {
super.cancel()
task?.cancel()
}
}
, cancel, "", dataTask ( , ) super .
- , isCancelled. cancel, . :
class DisplayLinkOperation: AsynchronousOperation {
private weak var displayLink: CADisplayLink?
private var startTime: CFTimeInterval!
private let duration: CFTimeInterval = 2
override func main() {
startTime = CACurrentMediaTime()
let displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink(_:)))
displayLink.add(to: .main, forMode: .commonModes)
self.displayLink = displayLink
}
@objc func handleDisplayLink(_ displayLink: CADisplayLink) {
let percentComplete = (CACurrentMediaTime() - startTime) / duration
if percentComplete >= 1.0 || isCancelled {
displayLink.invalidate()
finish()
}
}
}
, , / , cancel, isCancelled , .
cancel, . , markAsCompleted isFinished isExecuting , , , .
, AsynchronousOperation , , . , markAsCompleted finish, , isFinished isExecuting , . , isFinished:
open class AsynchronousOperation: Operation {
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
private let stateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".rw.state", attributes: .concurrent)
private var rawState: OperationState = .ready
@objc private dynamic var state: OperationState {
get { return stateQueue.sync { rawState } }
set { stateQueue.sync(flags: .barrier) { rawState = newValue } }
}
open override var isReady: Bool { return state == .ready && super.isReady }
public final override var isExecuting: Bool { return state == .executing }
public final override var isFinished: Bool { return state == .finished }
public final override var isAsynchronous: Bool { return true }
open override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
if ["isReady", "isFinished", "isExecuting"].contains(key) {
return [#keyPath(state)]
}
return super.keyPathsForValuesAffectingValue(forKey: key)
}
public final override func start() {
if isCancelled {
state = .finished
return
}
state = .executing
main()
}
open override func main() {
fatalError("Subclasses must implement 'main'.")
}
public final func finish() {
if isExecuting { state = .finished }
}
}