正如@AirspeedVelocity建议的那样,我重写了如下代码以删除不必要的依赖项.我还使用Int作为inout参数来保持简单.输出始终是:
c之前:0
c之后:1
我无法弄清楚这里出了什么问题.
- func getUsers() {
- let u = ["bane","LiweiZ","rdtsc","ssivark","sparkzilla","Wogef"]
- var a = UserData()
- a.userIds = u
- a.dataProcessor()
- }
- struct UserData {
- var userIds = [String]()
- var counter = 0
- mutating func dataProcessor() -> () {
- println("counter: \(counter)")
- for uId in userIds {
- getOneUserApiData(uriBase + "user/" + uId + ".json",&counter)
- }
- }
- }
- func getOneUserApiData(path: String,inout c: Int) {
- var req = NSURLRequest(URL: NSURL(string: path)!)
- var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
- var session = NSURLSession(configuration: config)
- var task = session.dataTaskWithRequest(req) {
- (data: NSData!,res: NSURLResponse!,err: NSError!) in
- println("c before: \(c)")
- c++
- println("c after: \(c)")
- println("thread on: \(NSThread.currentThread())")
- }
- task.resume()
- }
谢谢.
Parameters can provide default values to simplify function calls and can be passed as in-out parameters,which modify a passed variable once the function has completed its execution@H_404_20@.
…
An in-out parameter has a value that is passed in to the function,is modified by the function,and is passed back@H_404_20@ out of the function to replace the original value.
在语义上,输入输出参数不是“call-by-reference”,而是“call-by-copy-restore”.
在您的情况下,只有当getOneUserApiData()返回时,计数器才会被写入后备,而不是在dataTaskWithRequest()回调中.
以下是您的代码中发生的情况
>在getOneUserApiData()调用时,将计数器0的值复制到c1
>闭包捕获c1
>调用dataTaskWithRequest()
> getOneUserApiData返回,并且 – unmodified – c1的值被写回到计数器
>对c2,c3,c4重复1-4程序……
> …从互联网上取货……
>调用回调并且c1递增.
>调用回调,c2递增.
>调用回调并且c3递增.
>调用回调并且c4递增.
> ……
因此,计数器未经修改:(
详细解释
通常,in-out参数通过引用传递,但它只是编译器优化的结果.当闭包捕获inout参数时,“传递引用”并不安全,因为编译器无法保证原始值的生命周期.例如,请考虑以下代码:
- func foo() -> () -> Void {
- var i = 0
- return bar(&i)
- }
- func bar(inout x:Int) -> () -> Void {
- return {
- x++
- return
- }
- }
- let closure = foo()
- closure()
在此代码中,当foo()返回时,将释放var i.如果x是对i的引用,则x会导致访问冲突.为了防止这种竞争条件,Swift采用了“逐个复制恢复”策略.