比方說,我有一個模型,用String
類型的屬性color
稱爲Car
:商店參考斯威夫特
class Car {
var color: String?
}
現在,我有另一個類稱爲Interface
,我想用它來修改數值的color
財產Car
。要做到這一點,我想以某種方式結合color
至Interface
的屬性,如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
的副本,而不是參考。這意味着修改storedKey
的interface
對corolla.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)
在我看來,這打破了至少兩個語義規則在斯威夫特:
withUnsafeMutablePointer
通過&
傳遞一個實例的地址轉換爲該實例的類型爲「」,僅在使用時纔在之間提供關閉。按照the Swift docs:body的指針參數只對封閉的生命週期有效。不要將它從閉合物中脫出以供以後使用。
- 第二個問題是,這利用了Swift編譯器優化,允許
bind
實際獲得對key
的引用而不是副本。否則,指針不會獲得對原始鍵的引用,而是獲得對副本的引用。inout
參數通常使用稱爲拷入拷貝的行爲來實現,其中參數的拷貝被傳遞給函數,可能被修改,然後被分配回原始參數。 As per the docs,有一個優化,如果參數是存儲的屬性,則在函數體內部和外部使用相同的存儲位置。這使得我們的指針可以獲得對原始String結構的引用,而不是副本,從而可以工作。作爲優化,當參數是存儲在內存中物理地址的值時,函數體內部和外部都使用相同的內存位置。
有什麼辦法來存儲爲String
這樣一個結構的參考?還是我在瘋狂的追逐?編輯1:另外,我不能控制Car
的屬性。
比較[斯威夫特:通過指針訪問計算屬性](http://stackoverflow.com/q/42798354/2976878) - 你可能只想要一個閉包。 – Hamish
您可能正在尋找「鏡頭」:http://chris.eidhof.nl/post/lenses-in-swift/ –