Apple的高级NSOperations示例代码中的竞争条件

时间:2016-07-17 15:00:15

标签: ios swift multithreading nsoperation

TL:DR

.Completed上设置NSURLSessionTask状态的时间是什么?它如何依赖/影响同一任务的completionHandler

有没有办法确保仅在.Completed执行完毕后才设置completionHandler状态?

问题

关于这里的另一个问题...... Chaining multiple async functions in Swift

我被指向了高级NSOperations WWDC TalkSample Code的方向。

在将部分代码复制到我自己的项目中之后,我发现我似乎遇到了竞争条件,有时会有效,有时会失败,具体取决于竞争条件的发挥方式。

我创建的操作几乎是示例代码中DownloadEarthquakesOperation的副本。

它是GroupOperation的子类,包含URLSessionTaskOperationNSURLSessionTask是使用completionHandler创建的,用于处理下载的数据。

URLSessionTaskOperation的工作原理是观察其任务的state属性,然后在将其更改为.Completed时完成操作。

我遇到的问题是,在state处理完毕之前,任务的.Completed似乎已更改为completionHandler

我拥有的完成处理程序就是这样......

// this is a direct copy of the sample code just using data task
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
    data, response, error in    
    self.downloadFinished(data, response: response as? NSHTTPURLResponse, error: error)
}

它调用的函数(伪代码)是这样的......(我现在无法访问确切的代码)。

func downloadFinished(data: NSData?, response: NSHTTPURLResponse?, error, NSError?) {
    // if the error is not nil then finish operation with error

    // if the response status code is not correct then finish with error

    // try to convert the data to a JSON object using NSJSONSerialization

    // finish with error if conversion failed

    // get a single Int value out of the JSON object

    // store the single Int value in an instance variable
}

这里没有异步代码。

完成此操作之后(相当于示例代码中的GetEarthquakesOperation)获取实例变量中的值并将其传递给下一个操作。

问题是有时这个值存在,有时它是零。

通过注销不同类中的各行,我可以看到网络操作在执行完成处理程序的某个时刻被设置为已完成。有时在设定值之前,有时在之后。

令人费解的是,我试图在示例应用程序中强制执行此操作,但我无法做到。我已经尝试了sleep完成处理程序,并且我尝试了一个很长的执行时间循环,但它们似乎都没有用。

任何人都可以帮我解决这种竞争状况。

1 个答案:

答案 0 :(得分:3)

好的,这很奇怪。

http://www.oliverfoggin.com/advanced-nsoperations-nsurlsessiondatatask-vs-nsurlsessiondownloadtask/

NSURLSessionDataTask和NSURLSessionDownloadTask都运行完成处理程序并以不同方式设置完成状态。

下载任务仅在完成处理程序执行完毕后将自身设置为已完成。

数据任务在完成处理程序开始执行后将自身设置为已完成。

这导致了我自己项目中的竞争状况。我想我现在就转而使用下载任务了。

我也会提交雷达。