First of all, if you pass a struct it gets normally passed by value. Even though all properties of the struct get copied only the pointer to properties which are reference types like UIImage gets duplicated (only 8 bytes):
var data1 = MyData()
var data2 = data1
// both data1 and data2 point to the same image
Also the compiler optimizes the code so structs get internally passed by reference and copied if needed.
As an example of passing a struct by reference in top level code you can use inout
parameters:
So an inout
parameter can be passed by reference but Swift's general way of implementing inout
is that the parameter gets passes by value and after the function returns it gets reassigned.
Although the compiler optimizes the function call so you could get a true reference in some situations. This optimization only affects variables which aren't computed or have a property observer like willSet
and didSet
(and probably other cases).
So you should only rely on the current instance which is not in the scope of the function:
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
As you can see myTest
and t
are only equivalent in case 1 ("true" reference semantics). So this makes a huge difference if you also reference myTest
in the function itself. But as long as you don't do this you are good to go.