Are swift classes inside struct passed by copy during assignment?

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.


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: &copy_b1) { (address) in
    print("address of copy_b1 (struct) = \(address)")
}
withUnsafePointer(to: &copy_b1.grade) { (address) in
    print("address of copy_b1.grade (struct) = \(address)")
}
withUnsafePointer(to: &copy_b1.a) { (address) in
    print("address of copy_b1.a (class) = \(address)")
}
withUnsafePointer(to: &copy_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 &copy_b1.a.id are referring the same address.


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