use*_*037 2 nsoperation ios swift
SomeOperation went isFinished=YES without being started by the queue it is in
public class SomeOperation : AsyncOperation {
//MARK: Start
public override func start() {
isExecuting = true
guard !isCancelled else {
markAsCompleted() //isExecuting = false, isFinished = true
return
}
doSomethingAsynchronously { [weak self] in
self?.markAsCompleted() //isExecuting = false, isFinished = true
}
}
//MARK: Cancel
public override func cancel() {
super.cancel()
markAsCompleted() //isExecuting = false, isFinished = true
}
}
Run Code Online (Sandbox Code Playgroud)
//someOperation is a property in a class
if let someOperation = someOperation {
queue.addOperation(someOperation)
}
//Based on some condition cancelling it
someOperation?.cancel()
Run Code Online (Sandbox Code Playgroud)
public override func cancel() {
isExecuting = true //Just in case the operation was cancelled before starting
super.cancel()
markAsCompleted()
}
Run Code Online (Sandbox Code Playgroud)
markAsCompleted集isExecuting = false和isFinished = trueisExecuting,isFinished是同步的属性KVO关键问题是你的操作不会markAsCompleted触发.我建议你只是解决这个问题,如果是真的那样做.这减少了子类执行任何复杂状态测试的负担,以确定它们是否需要转换.isFinishedisExecutingmarkAsCompletedisExecutingisFinished
话虽如此,我在编写可取消的异步操作时会看到三种基本模式:
如果我正在处理一些模式,其中取消任务将阻止它将执行操作转换为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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
专注于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() } // make sure to finish the operation
// process `data` & `error` here
}
task.resume()
self.task = task
}
override func cancel() {
super.cancel()
task?.cancel()
}
}
Run Code Online (Sandbox Code Playgroud)
再次,关注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()
}
// now do some UI update based upon `elapsed`
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我在一个操作中包装了一个显示链接,所以我可以管理依赖项和/或将显示链接封装在一个方便的对象中,我根本不需要实现cancel,因为默认实现将为isCancelled我更新,我可以检查一下.
这些是cancel我通常看到的三种基本模式.已经说过,更新markAsCompleted只是触发isFinished是否isExecuting是一个很好的安全检查,以确保你永远不会得到你描述的问题.
顺便AsynchronousOperation说一句,我用于上述示例的内容如下,改编自试图理解异步操作子类.BTW,你所谓markAsCompleted的叫做finish,听起来你是通过不同的机制触发isFinished和isExecutingKVO,但这个想法基本相同.在触发isFinishedKVO 之前,只需检查当前状态:
open class AsynchronousOperation: Operation {
/// State for this operation.
@objc private enum OperationState: Int {
case ready
case executing
case finished
}
/// Concurrent queue for synchronizing access to `state`.
private let stateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".rw.state", attributes: .concurrent)
/// Private backing stored property for `state`.
private var rawState: OperationState = .ready
/// The state of the operation
@objc private dynamic var state: OperationState {
get { return stateQueue.sync { rawState } }
set { stateQueue.sync(flags: .barrier) { rawState = newValue } }
}
// MARK: - Various `Operation` properties
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 }
// MARK: - KVN for dependent properties
open override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
if ["isReady", "isFinished", "isExecuting"].contains(key) {
return [#keyPath(state)]
}
return super.keyPathsForValuesAffectingValue(forKey: key)
}
// MARK: - Foundation.Operation
public final override func start() {
if isCancelled {
state = .finished
return
}
state = .executing
main()
}
/// Subclasses must implement this to perform their work and they must not call `super`. The default implementation of this function throws an exception.
open override func main() {
fatalError("Subclasses must implement `main`.")
}
/// Call this function to finish an operation that is currently executing
public final func finish() {
if isExecuting { state = .finished }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1409 次 |
| 最近记录: |