异步回调中的 Inout 参数未按预期工作 [英] Inout parameter in async callback does not work as expected
问题描述
我正在尝试使用 inout
参数插入函数,以将从异步回调接收到的数据附加到外部数组.但是,它不起作用.我尝试了我所知道的一切来找出原因 - 没有运气.
I'm trying to insert functions with inout
parameter to append data received from async callback to an outside array. However, it does not work. And I tried everything I know to find out why - with no luck.
根据@AirspeedVelocity 的建议,我将代码重写如下以删除不必要的依赖项.我还使用 Int
作为 inout
参数以保持简单.
输出始终为:c 之前:0
c after: 1
As advised by @AirspeedVelocity, I rewrote the code as follows to remove unnecessary dependencies. I also use an Int
as the inout
parameter to keep it simple.
The output is always:
c before: 0
c after: 1
我无法弄清楚这里出了什么问题.
I'm not able to figure out what goes wrong here.
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()
}
谢谢.
推荐答案
不幸的是,修改<代码> INOUT 代码>参数在异步回调是无意义的.
Sad to say, modifying inout
parameter in async-callback is meaningless.
来自官方文档:
参数可以提供默认值以简化函数调用,并且可以作为输入输出参数传递,一旦函数执行完毕就修改传递的变量.
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.
...
一个in-out参数有一个值,它传入函数,被函数修改,并传回出函数来代替原来的值.
An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.
从语义上讲,输入输出参数不是call-by-reference",但是call-by-copy-restore".
Semantically, in-out parameter is not "call-by-reference", but "call-by-copy-restore".
在您的情况下,counter
仅在 getOneUserApiData()
返回时回写,而不是在 dataTaskWithRequest()
回调中.
In your case, counter
is write-backed only when getOneUserApiData()
returns, not in dataTaskWithRequest()
callback.
这是您的代码中发生的事情
Here is what happened in your code
- 在
getOneUserApiData()
调用时,counter
0
的值被复制到c
1 - 闭包捕获
c
1 - 调用
dataTaskWithRequest()
getOneUserApiData
返回,并且 - 未修改 -c
1 的值被回写到counter
- 为
c
2、c
3、c
重复1-4个过程>4 ... - ...从互联网上获取...
- 回调被调用,
c
1 递增. - 回调被调用,
c
2 递增. - 回调被调用,
c
3 递增. - 回调被调用,
c
4 递增. - ...
- at
getOneUserApiData()
call, the value ofcounter
0
copied toc
1 - the closure captures
c
1 - call
dataTaskWithRequest()
getOneUserApiData
returns, and the value of - unmodified -c
1 is write-backed tocounter
- repeat 1-4 procedure for
c
2,c
3,c
4 ... - ... fetching from the Internet ...
- callback is called and
c
1 is incremented. - callback is called and
c
2 is incremented. - callback is called and
c
3 is incremented. - callback is called and
c
4 is incremented. - ...
结果 counter
没有被修改:(
As a result counter
is unmodified :(
详细说明
通常情况下,in-out
参数是通过引用传递的,但这只是编译器优化的结果.当闭包捕获 inout
参数时,pass-by-reference"不安全,因为编译器无法保证原始值的生命周期.例如,考虑以下代码:
Normally, in-out
parameter is passed by reference, but it's just a result of compiler optimization. When closure captures inout
parameter, "pass-by-reference" is not safe, because the compiler cannot guarantee the lifetime of the original value. For example, consider the following code:
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 采用了call-by-copy-restore".策略在这里.
In this code, var i
is freed when foo()
returns. If x
is a reference to i
, x++
causes access violation. To prevent such race condition, Swift adopts "call-by-copy-restore" strategy here.
这篇关于异步回调中的 Inout 参数未按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!