在异步块内改变输入函数参数
Mutate inout function paramter inside async block
我有以下 playground 代码:
import UIKit
import XCPlayground
class A {
var arr : [UIImage] = []
func addItem(inout localArr: [UIImage]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
localArr.append(UIImage())
print("from inside function localArr: \(localArr)")
print("form inside function: \(self.arr)")
}
}
}
let a = A()
a.addItem(&a.arr)
print("instant print :\(a.arr)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
print("print after delay: \(a.arr)")
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
输出为:
instant print :[]
from inside function localArr: [<UIImage: 0x7f99e8706f10>, {0, 0}]
form inside function: []
print after delay: []
我的问题是,为什么localArr
和addItem
里面的self.arr
不一样,和外面的a.arr
不一样?我的期望是,当我将参数作为 inout
传递时,我应该能够对实际对象而不是副本进行操作,但显然这不是发生的情况。
编辑:感谢 dfri 的回答,我知道为什么这不起作用。 inout
实际上是 call-by-copy-restore, check another answer 。现在,关于如何实际制作闭包以捕获对原始对象的引用的任何建议?或者我应该使用其他技术来实现我想要的?
有关 inout
关键字的一些理论,请参阅以下答案:
Do not depend on the behavioral differences between copy-in copy-out
and call by reference.
...
When the function returns, your changes to the original are
overwritten with the value of the copy. Do not depend on the
implementation of the call-by-reference optimization to try to keep
the changes from being overwritten.
现在,您的 addItem
函数将立即完成其调用,从而在函数中的延迟调度之前完成 inout
copy-in/copy-out 任务。这使得在inout
参数的方法中使用延迟调度本质上是不好的,至少如果延迟是试图改变inout
参数的延迟。
为了看到这一点,让我们跟踪一些数组的引用(而不是跟踪值),以及它们如何在我们的示例运行期间显示数组的变化。
func foo(inout bar: [Int]) {
var pBar : UnsafePointer<Int> = UnsafePointer(bar)
print("2: \(pBar)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
pBar = UnsafePointer(bar)
print("3: \(pBar)")
bar[0] = 2
pBar = UnsafePointer(bar)
print("4: \(pBar)")
}
}
var a : [Int] = [1]
var pA : UnsafePointer<Int> = UnsafePointer(a)
print("1: \(pA)")
foo(&a)
print("foo call to a finished, a = \(a)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(5 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
print("value of a naturally not changed here = \(a)")
pA = UnsafePointer(a)
print("5: \(pA)")
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
输出相当self-explanatory:
1: 0x00007fe19271e930
2: 0x00007fe19271e930
foo call to a finished, a = [1] <-- call to foo finished, 'inout' procedure complete
3: 0x00007fe19271e930 <-- dispatch in `foo` starts
4: 0x00007fe1927085e0 <-- mutates 'bar': 'bar' copied (and never
"returned" as this step is already finished)
value of a naturally not changed here = [1]
5: 0x00007fe19271e930 <-- naturally 'a' wont see the effect of the
delayed mutation in foo
Swift 数组是值类型。总是在分配时复制。
如果要引用原始数组,请使用 NSMutableArray。
那么也不需要inout
class A {
var arr : NSMutableArray = []
func addItem(localArr: NSMutableArray) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
localArr.addObject(UIImage())
print("from inside function localArr: \(localArr)")
print("form inside function: \(self.arr)")
}
}
}
let a = A()
a.addItem(a.arr)
print("instant print :\(a.arr)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
print("print after delay: \(a.arr)")
}
打印:
instant print :(
)
from inside function localArr: (
"<UIImage: 0x7ffe1872b5f0>, {0, 0}"
)
form inside function: (
"<UIImage: 0x7ffe1872b5f0>, {0, 0}"
)
print after delay: (
"<UIImage: 0x7ffe1872b5f0>, {0, 0}"
)
我有以下 playground 代码:
import UIKit
import XCPlayground
class A {
var arr : [UIImage] = []
func addItem(inout localArr: [UIImage]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
localArr.append(UIImage())
print("from inside function localArr: \(localArr)")
print("form inside function: \(self.arr)")
}
}
}
let a = A()
a.addItem(&a.arr)
print("instant print :\(a.arr)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
print("print after delay: \(a.arr)")
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
输出为:
instant print :[]
from inside function localArr: [<UIImage: 0x7f99e8706f10>, {0, 0}]
form inside function: []
print after delay: []
我的问题是,为什么localArr
和addItem
里面的self.arr
不一样,和外面的a.arr
不一样?我的期望是,当我将参数作为 inout
传递时,我应该能够对实际对象而不是副本进行操作,但显然这不是发生的情况。
编辑:感谢 dfri 的回答,我知道为什么这不起作用。 inout
实际上是 call-by-copy-restore, check another answer
有关 inout
关键字的一些理论,请参阅以下答案:
Do not depend on the behavioral differences between copy-in copy-out and call by reference.
...
When the function returns, your changes to the original are overwritten with the value of the copy. Do not depend on the implementation of the call-by-reference optimization to try to keep the changes from being overwritten.
现在,您的 addItem
函数将立即完成其调用,从而在函数中的延迟调度之前完成 inout
copy-in/copy-out 任务。这使得在inout
参数的方法中使用延迟调度本质上是不好的,至少如果延迟是试图改变inout
参数的延迟。
为了看到这一点,让我们跟踪一些数组的引用(而不是跟踪值),以及它们如何在我们的示例运行期间显示数组的变化。
func foo(inout bar: [Int]) {
var pBar : UnsafePointer<Int> = UnsafePointer(bar)
print("2: \(pBar)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
pBar = UnsafePointer(bar)
print("3: \(pBar)")
bar[0] = 2
pBar = UnsafePointer(bar)
print("4: \(pBar)")
}
}
var a : [Int] = [1]
var pA : UnsafePointer<Int> = UnsafePointer(a)
print("1: \(pA)")
foo(&a)
print("foo call to a finished, a = \(a)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(5 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
print("value of a naturally not changed here = \(a)")
pA = UnsafePointer(a)
print("5: \(pA)")
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
输出相当self-explanatory:
1: 0x00007fe19271e930
2: 0x00007fe19271e930
foo call to a finished, a = [1] <-- call to foo finished, 'inout' procedure complete
3: 0x00007fe19271e930 <-- dispatch in `foo` starts
4: 0x00007fe1927085e0 <-- mutates 'bar': 'bar' copied (and never
"returned" as this step is already finished)
value of a naturally not changed here = [1]
5: 0x00007fe19271e930 <-- naturally 'a' wont see the effect of the
delayed mutation in foo
Swift 数组是值类型。总是在分配时复制。
如果要引用原始数组,请使用 NSMutableArray。
那么也不需要inout
class A {
var arr : NSMutableArray = []
func addItem(localArr: NSMutableArray) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
localArr.addObject(UIImage())
print("from inside function localArr: \(localArr)")
print("form inside function: \(self.arr)")
}
}
}
let a = A()
a.addItem(a.arr)
print("instant print :\(a.arr)")
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) { () -> Void in
print("print after delay: \(a.arr)")
}
打印:
instant print :(
)
from inside function localArr: (
"<UIImage: 0x7ffe1872b5f0>, {0, 0}"
)
form inside function: (
"<UIImage: 0x7ffe1872b5f0>, {0, 0}"
)
print after delay: (
"<UIImage: 0x7ffe1872b5f0>, {0, 0}"
)