在Swift中存储对struct的引用

时间:2017-05-06 06:47:21

标签: swift

假设我有一个名为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 storedKeyinterface的值没有影响。

如果我们将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中的两个语义规则:

  1. 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的指针参数仅在闭包的生命周期内有效。不要将其从封盖中取出以备后用。

  2. 第二个问题是,这利用了Swift编译器优化,允许UnsafeMutablePointer实际获得对bind的引用而不是副本。否则,指针将不会获得对原始键的引用,而是获取对副本的引用。 key参数通常使用称为copy-in copy-out的行为来实现,其中参数的副本传递给函数,可能已修改,然后分配回原始参数。 the Swift docs,有一个优化,如果参数是存储属性,则在函数体内部和外部使用相同的内存位置。这允许我们的指针获取对原始String结构的引用而不是副本,从而允许它工作。
      

    作为优化,当参数是存储在内存中物理地址的值时,在函数体内部和外部都使用相同的内存位置。

  3. 有没有办法存储对inout等结构的引用?或者我正在疯狂追逐?

    编辑1:此外,我无法控制String属性的类型。

1 个答案:

答案 0 :(得分:0)

您已经研究过,无法获得对结构的引用。

你可以做的是使用Box类并传递它。

然后你可以随处使用Box,并在需要的地方访问它的struct属性。

类似的东西:

class Box<T> {
   var value: T
   init(value: T) {
      self.value = value
   }
}

并将其与汽车一起使用

let boxedCar = Box(value: Car(...)) 

您可以共享对此框的引用,并始终通过值属性

访问汽车