gpt4 book ai didi

ios - 重置 NSOperation

转载 作者:行者123 更新时间:2023-11-28 06:40:13 26 4
gpt4 key购买 nike

我的网络请求需要以 FIFO 串行方式发生。如果由于网络问题(即离线、超时)而失败,我需要失败的请求在继续队列之前重试。我怎样才能做到这一点?

当操作失败时,我将执行和完成都设置为 - 假设这将作为 NSOperation 的“重置”。但是队列永远不会恢复。

有什么我想念的吗?

最佳答案

您可以构建一个执行重试的网络操作,并且仅在调用网络完成 block 时设置 isFinished,并确定不需要重试:

class NetworkOperationWithRetry: AsynchronousOperation {
var session: NSURLSession
var request: NSURLRequest
var task: NSURLSessionTask?
var networkCompletionHandler: ((NSData?, NSURLResponse?, NSError?) -> ())?

init(session: NSURLSession = NSURLSession.sharedSession(), request: NSURLRequest, networkCompletionHandler: (NSData?, NSURLResponse?, NSError?) -> ()) {
self.session = session
self.request = request
self.networkCompletionHandler = networkCompletionHandler
}

override func main() {
attemptRequest()
}

func attemptRequest() {
print("attempting \(request.URL!.lastPathComponent)")

task = session.dataTaskWithRequest(request) { data, response, error in
if error?.domain == NSURLErrorDomain && error?.code == NSURLErrorNotConnectedToInternet {
print("will retry \(self.request.URL!.lastPathComponent)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * Int64(NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
self.attemptRequest()
}
return
}

print("finished \(self.request.URL!.lastPathComponent)")

self.networkCompletionHandler?(data, response, error)
self.networkCompletionHandler = nil
self.completeOperation()
}
task?.resume()
}

override func cancel() {
task?.cancel()
super.cancel()
}
}

你可以这样调用它:

let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 1 // I wouldn't generally do this, but just to illustrate that it's honoring operation queue dependencies/concurrency settings

let requests = urlStrings.map { NSURLRequest(URL: NSURL(string: $0)!) }
requests.forEach { request in
queue.addOperation(NetworkOperationWithRetry(request: request) { data, response, error in
// do something with the `data`, `response`, and `error`
})
}

现在,这只是在 NSURLErrorNotConnectedToInternet 上重试,但您可以根据需要更改该逻辑。同样,我可能倾向于添加一些“最大重试”逻辑。此外,如果缺少 Internet 连接确实是问题所在,而不是在实现 Internet 连接之前重试,我可能倾向于将操作的 isReady 通知设置为可达性。

顺便说一句,上面使用了下面的AsynchronousOperation:

/// 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 : NSOperation {

override public var asynchronous: Bool { return true }

private let stateLock = NSLock()

private var _executing: Bool = false
override private(set) public var executing: Bool {
get {
return stateLock.withCriticalScope { _executing }
}
set {
willChangeValueForKey("isExecuting")
stateLock.withCriticalScope { _executing = newValue }
didChangeValueForKey("isExecuting")
}
}

private var _finished: Bool = false
override private(set) public var finished: Bool {
get {
return stateLock.withCriticalScope { _finished }
}
set {
willChangeValueForKey("isFinished")
stateLock.withCriticalScope { _finished = newValue }
didChangeValueForKey("isFinished")
}
}

/// Complete the operation
///
/// This will result in the appropriate KVN of isFinished and isExecuting

public func completeOperation() {
if executing {
executing = false
}

if !finished {
finished = true
}
}

override public func start() {
if cancelled {
finished = true
return
}

executing = true

main()
}

override public func main() {
fatalError("subclasses must override `main`")
}
}

extension NSLock {

/// Perform closure within lock.
///
/// An extension to `NSLock` to simplify executing critical code.
///
/// - parameter block: The closure to be performed.

func withCriticalScope<T>(@noescape block: Void -> T) -> T {
lock()
let value = block()
unlock()
return value
}
}

关于ios - 重置 NSOperation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38168506/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com