假设我有一个名为Car
的模型,其属性color
的类型为String
:
class Car {
var color: String?
}
现在,我有另一个名为Interface
的类,我希望用它来修改color
的{{1}}属性的值。为此,我想以某种方式将Car
绑定到color
的属性,例如Interface
:
key
用法:
class Interface {
var storedKey: String?
func bind(key: String?) {
self.storedKey = key
}
}
这种方法失败,因为字符串是Swift中的值类型(结构),因此let corolla = Car()
corolla.color = "green"
let interface = Interface()
interface.bind(key: &corolla.color)
interface.storedKey = "blue"
print(corolla.color) // still "green"! :(
函数获取bind
的副本,而不是引用。这意味着修改corolla.color
storedKey
对interface
的值没有影响。
如果我们将corolla.color
添加到绑定函数中,如下所示,我们基本上获得对传入的键的引用(it's actually copied in then copied out),但它只持续函数的范围。
inout
结果相同,修改func bind(key: inout String?) {
self.storedKey = key // assignment of value type is a copy! :/
}
对其绑定的属性没有影响。
归结为什么,我们可以在Swift中获得对结构的引用吗?
由于结构占用内存中的空间,我们可能能够获得指向传入的键的指针,这是一个有效的(不正确的)解决方案:
storedKey
在我看来,这至少打破了Swift中的两个语义规则:
class Car {
var color: String?
}
let corolla = Car()
corolla.color = "green"
class Interface {
var storedKey: UnsafeMutablePointer<String?>?
func bind(_ key: inout String?) {
self.storedKey = withUnsafeMutablePointer(to: &key) { ptr in
return ptr
}
}
}
var interface = Interface()
interface.bind(&corolla.color)
interface.storedKey?.pointee = "blue" // :O it's... working?
print(corolla.color)
将通过withUnsafeMutablePointer
传入的实例的地址转换为该实例类型的&
,仅在中使用提供的封闭。根据{{3}}:
body的指针参数仅在闭包的生命周期内有效。不要将其从封盖中取出以备后用。
UnsafeMutablePointer
实际获得对bind
的引用而不是副本。否则,指针将不会获得对原始键的引用,而是获取对副本的引用。 key
参数通常使用称为copy-in copy-out的行为来实现,其中参数的副本传递给函数,可能已修改,然后分配回原始参数。 the Swift docs,有一个优化,如果参数是存储属性,则在函数体内部和外部使用相同的内存位置。这允许我们的指针获取对原始String结构的引用而不是副本,从而允许它工作。
作为优化,当参数是存储在内存中物理地址的值时,在函数体内部和外部都使用相同的内存位置。
有没有办法存储对inout
等结构的引用?或者我正在疯狂追逐?
编辑1:此外,我无法控制String
属性的类型。
答案 0 :(得分:0)
您已经研究过,无法获得对结构的引用。
你可以做的是使用Box类并传递它。
然后你可以随处使用Box,并在需要的地方访问它的struct属性。
类似的东西:
class Box<T> {
var value: T
init(value: T) {
self.value = value
}
}
并将其与汽车一起使用
let boxedCar = Box(value: Car(...))
您可以共享对此框的引用,并始终通过值属性
访问汽车