同様の質問を検討しましたが、満足する回答がありません。
構造体を参照で渡すことは可能ですか、それともお勧めですか?もしそうなら?
例の参照としてのコードは次のとおりです。
struct MyData {
var contentId: Int = 0
var authorId: Int = 0
var image: UIImage = UIImage(named: "myimage")
}
ご覧のとおり、これを行う主な理由は、私のイメージがいたるところに増殖していないためです。
構造体は、inout
キーワードと&
演算子を使用して参照渡しすることができます。
struct Test {
var val1:Int
let val2:String
init(v1: Int, v2: String) {
val1 = v1
val2 = v2
}
}
var myTest = Test(v1: 42, v2: "fred")
func change(test: inout Test) {
// you can mutate "var" members of the struct
test.val1 = 24
// or replace the struct entirely
test = Test(v1: 10, v2: "joe")
}
change(test: &myTest)
myTest // shows val1=10, val2=joe in the playground
重要な状況で必要なパフォーマンスを得る唯一の方法であることが証明できない限り、この方法はお勧めできません。
これを行っても、UIImageをコピーする負担を軽減できないことに注意してください。参照型を構造体のメンバーとして配置しても、値で渡す場合にのみ参照をコピーします。画像の内容をコピーしていません。
構造体のパフォーマンスについて知っておくべきもう1つの重要なことは、copy-on-writeです。 Arrayのような組み込み型の多くは値型ですが、非常に高性能です。 Swiftで構造体を渡す場合、変異するまで、構造体をコピーする負担はかかりません。
詳細については、 値の型に関するWWDCビデオ を参照してください。
まず、構造体を渡すと、通常は値で渡されます。構造体のすべてのプロパティはコピーされますが、UIImageのような参照型であるプロパティへのポインタのみが複製されます(8バイトのみ)。
var data1 = MyData()
var data2 = data1
// both data1 and data2 point to the same image
また、コンパイラーはコードを最適化するため、構造体は内部的に参照渡しされ、必要に応じてコピーされます。
トップレベルのコードで構造体を参照渡しする例として、inout
パラメータを使用できます。つまり、inout
パラメータを参照渡しできますが、inout
を実装するSwiftの一般的な方法つまり、パラメーターは値で渡され、関数が返された後、再割り当てされます。
コンパイラーは関数呼び出しを最適化するため、状況によっては真の参照を取得できます。この最適化は、計算されない変数、またはwillSet
やdidSet
などのプロパティオブザーバーを持つ変数にのみ影響します(おそらく他の場合も)。
したがって、関数のスコープ内にない現在のインスタンスのみに依存する必要があります。
struct Test {
var value = 0
}
// case 1
var myTest = Test()
// case 2
var myTest = Test() {
didSet { print("I was set") }
}
// case 3
var myTest: Test {
get{ return Test() }
set{ print("I set myself") }
}
func mutateTest(inout t: Test) {
// directly referencing to myTest
myTest.value // value = 0 in all cases
t.value = 42
myTest.value // value = 42 in case 1 ; value = 0 in case 2 and 3
t = Test() // nothing gets printed
myTest.value // value = 0 in all cases
t = Test() // nothing gets printed
t.value = 3 // value = 3 in case 1 ; value = 0 in case 2 and 3
}
changeTest(&myTest)
//case 2: "I was set", case 3 "I set myself" get printed now
myTest.value // value = 3 in all cases
ご覧のように、myTest
とt
は、ケース1(「true」参照セマンティクス)の場合にのみ同等です。したがって、関数自体でmyTest
も参照する場合、これは大きな違いになります。しかし、これを行わない限り、行ってもかまいません。