我尝试编写一个“编辑器”类,它可以保留对不同对象上的属性的引用,以便以后进行突变。我首先编写了编辑器类来接收一个用于读取的闭包,以及一个用于写入的闭包。这很有效。然后我尝试通过(inout)引用传递有问题的参数,然后从中生成getter / setter对。这没用。 Swift文档确实说(释义)Swift确定何时复制,何时不复制。我认为我反对这种限制的不可预测性,但我认为我提出的问题是一样的。
或者,是否可以为个别的getter和setter获得一个curried函数?
我的代码是:
class SomeModel : Printable {
var a:String
init(a:String) {
self.a = a
}
var description:String {
return "\(self.a)"
}
}
class Editor {
var getter:()-> String
var setter:(String)->()
init(getter:()-> String, setter:(String)->()) {
self.getter = getter
self.setter = setter
}
convenience init(inout bindTo:String) {
self.init(
getter:{ return bindTo },
setter: { v in bindTo = v })
}
func read() -> String {
return self.getter()
}
func write(value:String) {
self.setter(value)
}
}
func testBindTo() {
var readModel = SomeModel(a:"Did not capture by reference");
var bindForReading = Editor(bindTo: &readModel.a)
readModel.a = "captured by reference!"
println(bindForReading.read())
var writeModel = SomeModel(a:"Did not capture by reference");
var bindForWriting = Editor(bindTo: &writeModel.a)
bindForWriting.write("captured by reference")
println(writeModel)
}
testBindTo()
func testExplicitGetterSetter() {
var readModel = SomeModel(a:"Did not capture by reference");
var bindForReading = Editor(
getter: { readModel.a },
setter: { v in readModel.a = v })
readModel.a = "captured by reference!"
println(bindForReading.read())
var writeModel = SomeModel(a:"Did not capture by reference");
var bindForWriting = Editor(
getter: { writeModel.a },
setter: { v in writeModel.a = v })
bindForWriting.write("captured by reference")
println(writeModel)
}
testExplicitGetterSetter()
结果是:
Did not capture by reference
Did not capture by reference
captured by reference!
captured by reference
谢谢!
答案 0 :(得分:5)
我不认为这是可能的。如果你想的话,不应该是可能的,因为它会超级不安全。
因为闭包可以比它们创建的范围更长,所以捕获的变量必须与块一起存储。但是为了能够分配给捕获的变量并在捕获它的(一个或多个)块和原始范围之间共享该变量的状态,这些块不能只捕获变量的值(将创建变量的独立副本),但捕获一种"参考"到共享副本。这意味着必须特别存储由块捕获的可分配变量。在Objective-C中,这是使用__block
声明的。在Swift中,这种__block
行为是隐含的。
但是,为了让块修改inout
变量(可能在稍后的时间),如在函数调用者的范围中所见,这将意味着调用者中传递的变量& #39;范围也需要以比堆栈帧更长的方式存储。但是来电者的功能并不知道这一点。它从被调用函数的类型知道它的一个参数是inout
;它不知道该函数计划捕获块中的inout
变量。因此,它不知道为此传递的变量准备此__block
存储。
答案 1 :(得分:0)
可以如下进行。 )请注意,闭包和inout参数的寿命相同。)
/// A class providing access to a resource with an inout parameter in an escaping closure.
class ProtectedResource<ValueType> {
private var protectedResourceArray = [ValueType]()
private var protectedResourceArrayLock = NSRecursiveLock()
private let opq = OperationQueue()
func performWithResource(block: @escaping (inout [ValueType]) -> ()) {
opq.addOperation { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.protectedResourceArrayLock.lock()
block(&strongSelf.protectedResourceArray)
strongSelf.protectedResourceArrayLock.unlock()
}
}
}
/// Some other class using that in out parameter.
func run() {
func updateArray(array: inout [String]) {
print("Performing on \(array)")
array.append("test")
}
protectedResource.performWithResource(block: updateArray)
protectedResource.performWithResource {
print("Performing on \($0)")
}
}