2017-05-06 68 views
0
结构

比方说,我有一个模型,用String类型的属性color称为Car商店参考斯威夫特

class Car { 
    var color: String? 
} 

现在,我有另一个类称为Interface,我想用它来修改数值的color财产Car。要做到这一点,我想以某种方式结合colorInterface的属性,如key

class Interface { 

    var storedKey: String? 

    func bind(key: String?) { 
     self.storedKey = key 
    } 
} 

用法:

let corolla = Car() 
corolla.color = "green" 
let interface = Interface() 
interface.bind(key: &corolla.color) 
interface.storedKey = "blue" 
print(corolla.color) // still "green"! :(

因为字符串值类型(结构)在这种方法失败Swift,因此bind函数获得corolla.color的副本,而不是参考。这意味着修改storedKeyinterfacecorolla.color的值没有影响。

如果我们将inout添加到如下所示的绑定函数中,我们基本上获得了传入的密钥的引用(it's actually copied in then copied out),但它只是作用于该函数的作用域。

func bind(key: inout String?) { 
    self.storedKey = key // assignment of value type is a copy! :/ 
} 

结果是一样的,修改storedKey对它所绑定的属性没有影响。

这可以归结为什么,我们可以在Swift中获得对struct的引用吗?


由于结构占用的内存空间,我们也许能够获得一个指向传递的关键,这里是工作(不正确)解决方案:

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) 

在我看来,这打破了至少两个语义规则在斯威夫特:

  1. withUnsafeMutablePointer通过&传递一个实例的地址转换为该实例的类型为“”,仅在使用时才在之间提供关闭。按照the Swift docs

    body的指针参数只对封闭的生命周期有效。不要将它从闭合物中脱出以供以后使用。

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

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

有什么办法来存储为String这样一个结构的参考?还是我在疯狂的追逐?编辑1:另外,我不能控制Car的属性。

+1

比较[斯威夫特:通过指针访问计算属性](http://stackoverflow.com/q/42798354/2976878) - 你可能只想要一个闭包。 – Hamish

+1

您可能正在寻找“镜头”:http://chris.eidhof.nl/post/lenses-in-swift/ –

回答

0

您不能像您已经研究的那样获得对您的结构的引用。

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

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

喜欢的东西:

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

,并用汽车使用

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

您可以共享引用此框,并随时通过汽车通过价值性能

+0

我看过这种方法,但它不起作用,因为写入'value'属性box类对绑定的'String'没有影响,因为赋值'self.value = value'是一个副本。 – paulvs

+0

你正在装上已经是班级的'Car'。我曾想过装箱汽车的属性,但我无法控制'Car'属性的类型(我将编辑问题以反映这一点)。 – paulvs

+0

如果你总是通过盒子访问汽车,那么修改结构(并因此只是设置一个新的属性),每个人都可以通过盒子访问它,不是吗? –