If I have a struct in swift with inside a class attribute and I copy the struct object, is the class attribute copied or passed by reference?
4 Answers
Passed by reference. You can test it. Declare:
class A{}
struct B { let a = A()}
then:
let b = B()
print("A = \(unsafeAddressOf(b.a))")//0x0000600000019450
let b_copy = b
print("A = \(unsafeAddressOf(b_copy.a))")//0x0000600000019450

- 21,488
- 17
- 97
- 161
-
To make it work with swift 5 use: print(Unmanaged.passUnretained(b.a).toOpaque()) – user832 Jun 10 '20 at 16:52
-
Why isn't init called again? – Rajesh Budhiraja Aug 30 '21 at 11:41
-
Will it increment the reference count also? – Kaunteya Aug 03 '23 at 07:12
-
of course it will increment the reference count of a by one – Andrey Chernukha Aug 03 '23 at 09:11
All properties of a struct are copied (as if you assigned (=
) each property of the old struct to the corresponding property of the new struct) when the struct is copied, regardless of type.
When you say "class attribute", I am assuming you mean a variable of reference type. (The type with the same name as a class denotes a reference type for references that point to objects of that class.) Copying a value of reference type (a reference) produces another reference that points to the same object. Note that "objects" are not values in Swift -- there are no "object types" -- rather, objects are always manipulated through references that point to them.

- 119,665
- 29
- 163
- 224
-
Objects can be represented without reference that points to them if it is a value type object (struct) and it has less then 3 words (ivars) in it's contents. Type of those ivars must allow them to be be allocated on stack. In other case object will be allocated on the heap with corresponding pointer. Source https://developer.apple.com/videos/play/wwdc2016/416/ – Alexander Stepanishin Mar 19 '18 at 08:01
I tested the above experiment in swift 5: Let's see the result:
class A {
var id: Int
init(id: Int) {
self.id = id
}
}
struct B {
var grade: Int
var a: A
}
Experiment based on the result:
var a = A(id: 1)
var a_copy = a
var b1 = B(grade: 2, a: a)
var copy_b1 = b1
print(b1.a.id)
b1.a.id = 5
print(copy_b1.a.id)
print(b1.grade)
b1.grade = 3
print(copy_b1.grade)
Output:
1
5 // call by reference, same result
2
2 // call by value, no change in result
Conclusion:
struct does copy when we create another object of it. It copies its struct property (call by value) but refer the same instance of class property (call by reference)
Do experiment via address:
Do an Experiment on Class:
var a = A(id: 1)
var a_copy = a
withUnsafePointer(to: &a) { (address) in
print("address of a (class) = \(address)")
}
withUnsafePointer(to: &a_copy) { (address) in
print("address of a_copy (class) = \(address)")
}
withUnsafePointer(to: &a.id) { (address) in
print("address of a.id (struct) = \(address)")
}
withUnsafePointer(to: &a_copy.id) { (address) in
print("address of a_copy.id (struct) = \(address)")
}
Output
address of a (class) = 0x0000000114747f80
address of a_copy (class) = 0x0000000114747f88
address of a.id (struct) = 0x000060000285a390
address of a_copy.id (struct) = 0x000060000285a390
Observation 1:
Both instances of the class are referring to same location of its property.
Let's do the Experiment on struct:
print("\n\n\n")
withUnsafePointer(to: &b1) { (address) in
print("address of b1 (struct) = \(address)")
}
withUnsafePointer(to: &b1.grade) { (address) in
print("address of b1.grade (struct) = \(address)")
}
withUnsafePointer(to: &b1.a) { (address) in
print("address of b1.a (class) = \(address)")
}
withUnsafePointer(to: &b1.a.id) { (address) in
print("address of b1.a.id (class) = \(address)")
}
Output:
address of b1 (struct) = 0x0000000109382770
address of b1.grade (struct) = 0x0000000109382770
address of b1.a (class) = 0x0000000109382778
address of b1.a.id (class) = 0x0000600001e5cfd0
print("\n\n\n")
withUnsafePointer(to: ©_b1) { (address) in
print("address of copy_b1 (struct) = \(address)")
}
withUnsafePointer(to: ©_b1.grade) { (address) in
print("address of copy_b1.grade (struct) = \(address)")
}
withUnsafePointer(to: ©_b1.a) { (address) in
print("address of copy_b1.a (class) = \(address)")
}
withUnsafePointer(to: ©_b1.a.id) { (address) in
print("address of copy_b1.a.id (class) = \(address)")
}
Output:
address of copy_b1 (struct) = 0x0000000109382780
address of copy_b1.grade (struct) = 0x0000000109382780
address of copy_b1.a (class) = 0x0000000109382788
address of copy_b1.a.id (class) = 0x0000600001e5cfd0
conclusion: both &b1.a.id and ©_b1.a.id are referring the same address.

- 2,176
- 3
- 16
- 17
Seems, we have to consider modifying the object (as the optimizer will use the copy-on-write technique)
Value Type (User) contains Reference Type (Address)
observation:
- On assignment of value type, any value type (ex: User) that contains a reference type (ex: Address), that reference type (ex: Address) is always passed as a reference.
Reference Type (User) contains Value Types (Address)
observation:
- On assignment of reference type, any reference type (ex: User) contains value types (ex: Address), that value types (ex: Address) point to the same parent reference object (ex: User) (parent may contain many references - ex: both u1, u2 refers to same memory address).

- 403
- 8
- 13