嗨,我有一个奇怪的情况:
概述
我正在开发一个应用程序,用户可以在其中启动多个操作,所有这些操作都将在后台线程上运行,因此不会阻止UI。其中一些操作相互依赖,而另一些则不相关。 因此,为了确保只有在使用Operation的dependency属性完成所有必要的依赖操作后才能执行操作。我正在使用异步操作。
这是我的实施:
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network enableSsl="true" />
</smtp>
</mailSettings>
它的作用:
每个操作都会接受一个Web请求并尝试从服务器获取数据,如果失败,它会尝试3次,最后通过调用import UIKit
import CoreData
import SwiftyJSON
class VMBaseOperation: NSOperation {
var finishedStatus : Bool = false
var executionStatus : Bool = false
var retryCount : Int = 0
private (set) var requestToQueue : BaseRequest? = nil
var vmOperationCompletionBlock: ((JSON?) -> Void)?
var vmOperationFailureBlock: ((WebResponseError?) -> Void)?
override init() {
super.init()
}
convenience init(withVMRequest request : BaseRequest) {
self.init()
requestToQueue = request
}
override func start() {
if self.cancelled {
self.finished = true
return
}
NSThread.detachNewThreadSelector(#selector(main), toTarget: self, withObject: nil)
self.executionStatus = true
}
override func main() {
if self.cancelled {
return
}
self.hitWebService()
}
func hitWebService(){
let webserviceManager = WebServiceManager()
webserviceManager.getResponseFromRequest(requestToQueue!) { (requset, response, data, error) in
let error = WebResponseError.checkResponse(response, request: requset, error: error)
if error != nil {
if error == WebResponseError.NO_INTERNET {
if self.vmOperationFailureBlock != nil {
self.vmOperationFailureBlock!(error)
}
self.operationFailed()
}
else{
self.retryCount += 1
if self.retryCount == 3 {
if self.vmOperationFailureBlock != nil {
self.vmOperationFailureBlock!(error)
}
self.operationFailed()
}
else{
self.hitWebService()
}
}
}
else{
if data == nil {
self.retryCount += 1
if self.retryCount == 3 {
if self.vmOperationFailureBlock != nil {
self.vmOperationFailureBlock!(nil)
}
self.operationFailed()
}
else{
self.hitWebService()
}
}
else{
let json = JSON(data: data!)
if self.vmOperationCompletionBlock != nil {
self.vmOperationCompletionBlock!(json)
}
self.operationCompleted()
}
}
}
}
override var finished: Bool {
get{
return finishedStatus
}
set{
self.willChangeValueForKey("isFinished")
finishedStatus = newValue
self.didChangeValueForKey("isFinished")
}
}
override var executing: Bool {
get{
return executionStatus
}
set{
self.willChangeValueForKey("isExecuting")
executionStatus = newValue
self.didChangeValueForKey("isExecuting")
}
}
override var asynchronous: Bool{
get{
return true
}
set{
self.willChangeValueForKey("isAsynchronous")
self.asynchronous = true
self.didChangeValueForKey("isAsynchronous")
}
}
func operationCompleted(){
self.executing = false
self.finished = true
}
func operationFailed(){
self.executing = false
self.finished = false
}
}
方法将其完成状态设置为false,然后停止所有相关操作永远执行。另一方面,如果成功,它通过调用operationFailed
将其完成状态更改为true,从而触发执行剩余的相关操作。
问题是什么:
依赖性就像魅力一样。没问题。现在,无论操作队列中的所有操作是否成功完成,我都需要从服务器同步数据。
最简单的方法是创建一个操作来同步服务器中的数据,并将其作为依赖操作添加到添加到operationQueue的所有操作中。
但是由于上述操作的性质,即使一个操作失败也会停止所有相关操作的执行(如预期的那样),但由于我的服务器操作的同步数据也是一个依赖操作,它永远不会执行即使一次操作失败:(
我需要什么:
在保持上面提到的依赖关系的同时,我需要知道当操作队列中的所有操作完成执行时,无论它们是成功还是失败,如何执行从服务器同步数据的操作。
这是否可能:(请帮帮我。提前致谢。
答案 0 :(得分:2)
别介意我弄明白了:)
将完成状态设置为true和false会触发NSOperationQueue的KVO,从而启动或取消相关操作的操作。
如果我希望我的操作在任何时候执行,无论依赖操作是否成功完成,我都无法使用完成标志。在这种情况下,finished flag应该始终为true,表示操作已完成执行。
但是我如何确保对那些具有依赖关系的操作管理正派链,并且实际上取决于先前的操作是否成功?简单的我在我的NSOperationSubclass中添加了另一个名为finishedSuccessfully的变量。
当操作失败但将finished标志设置为true时,它会将finishedSuccessfully设置为false。这将导致相关操作start方法被调用。
在依赖操作的start方法中,它将遍历所有依赖操作,并且所有这些操作都以finishedSuccessfully = true完成。
如果是,则表示所有依赖操作都已完成执行并成功完成,因此可以开始执行。另一方面,如果其中任何一个已经完成成功=假,这意味着操作已完成执行但未能执行它应该执行的任何操作,因此此操作也应该自行停止并通知其依赖者它已完成finishSuccessfully = false。
摘要:
只有在所有依赖操作执行完毕后,无论操作是否成功,操作都将执行。
实际关注其依赖操作执行状态的操作将检查状态,然后最终决定是否继续执行。
维护依赖链以及确认同步操作也执行:)
这是我的实施:
import UIKit
import CoreData
import SwiftyJSON
class VMBaseOperation: NSOperation {
var finishedSuccessfully : Bool = false
var finishedStatus : Bool = false
var executionStatus : Bool = false
var retryCount : Int = 0
private (set) var requestToQueue : BaseRequest? = nil
var vmOperationCompletionBlock: ((JSON?) -> Void)?
var vmOperationFailureBlock: ((WebResponseError?) -> Void)?
override init() {
super.init()
}
convenience init(withVMRequest request : BaseRequest) {
self.init()
requestToQueue = request
}
override func start() {
if self.cancelled {
self.finished = true
return
}
//those operations which actually wants to know if all its dependency operations finished successfully or not can create a subclass of this class override start method and add the below code
for operation in self.dependencies {
if (operation as! VMBaseOperation).finishedSuccessfully == false {
self.operationFailed()
return
}
}
//others can ignore.
NSThread.detachNewThreadSelector(#selector(main), toTarget: self, withObject: nil)
self.executionStatus = true
}
override func main() {
if self.cancelled {
return
}
self.hitWebService()
}
func hitWebService(){
let webserviceManager = WebServiceManager()
webserviceManager.getResponseFromRequest(requestToQueue!) { (requset, response, data, error) in
let error = WebResponseError.checkResponse(response, request: requset, error: error)
if error != nil {
if error == WebResponseError.NO_INTERNET {
if self.vmOperationFailureBlock != nil {
self.vmOperationFailureBlock!(error)
}
self.operationFailed()
}
else{
self.retryCount += 1
if self.retryCount == 3 {
if self.vmOperationFailureBlock != nil {
self.vmOperationFailureBlock!(error)
}
self.operationFailed()
}
else{
self.hitWebService()
}
}
}
else{
if data == nil {
self.retryCount += 1
if self.retryCount == 3 {
if self.vmOperationFailureBlock != nil {
self.vmOperationFailureBlock!(nil)
}
self.operationFailed()
}
else{
self.hitWebService()
}
}
else{
let json = JSON(data: data!)
if self.vmOperationCompletionBlock != nil {
self.vmOperationCompletionBlock!(json)
}
self.operationCompleted()
}
}
}
}
override var finished: Bool {
get{
return finishedStatus
}
set{
self.willChangeValueForKey("isFinished")
finishedStatus = newValue
self.didChangeValueForKey("isFinished")
}
}
override var executing: Bool {
get{
return executionStatus
}
set{
self.willChangeValueForKey("isExecuting")
executionStatus = newValue
self.didChangeValueForKey("isExecuting")
}
}
override var asynchronous: Bool{
get{
return true
}
set{
self.willChangeValueForKey("isAsynchronous")
self.asynchronous = true
self.didChangeValueForKey("isAsynchronous")
}
}
func operationCompleted(){
self.executing = false
self.finished = true
}
func operationFailed(){
self.finishedSuccessfully = false
self.operationCompleted()
}
func operationSucceeded(){
self.finishedSuccessfully = true
self.operationCompleted()
}
}
答案 1 :(得分:2)
使用您的实施operationFailed
:
func operationFailed(){
self.executing = false
self.finished = false
}
你打破了NSOperation的原生逻辑:
操作依赖性
依赖关系是在特定操作中执行操作的便捷方式 订购。您可以使用。添加和删除操作的依赖项 addDependency:和removeDependency:方法。默认情况下,一个操作 具有依赖关系的对象在其全部之前不被认为是准备好的 依赖操作对象已完成执行。一旦到最后 然而,依赖操作结束,操作对象变为 准备好并且能够执行。
NSOperation支持的依赖关系没有区别 依赖操作是成功完成还是失败。 (换句话说,取消操作同样将其标记为 完成。)由您决定是否使用进行操作 依赖关系应该在其依赖操作的情况下进行 已取消或未成功完成任务。这可能 要求您加入一些额外的错误跟踪功能 进入你的操作对象。
如果操作失败,应按设计完成。但它可能以某种方式标记自己(某些特殊属性或cancelled
)。
依赖操作应检查是否可以启动。像下面这样的东西应该做的工作:
var requireDependencesCompletion: Bool = true
override var ready: Bool {
if requireDependencesCompletion
{
for op in self.dependencies {
if op.cancelled {
cancel()
}
}
super.ready
}
这里我们覆盖ready
属性以确定应该做什么。如果requireDependencesCompletion
为true
,则操作将检查其所有依赖关系,并在其中一个被取消时取消自身。
将requireDependencesCompletion
设置为true
进行典型操作,将false
设置为障碍操作,以便在任何情况下都可以启动。