< Which classes should be declared as final? | Why do classes have deinitializers and structs don’t? > |
Updated for Xcode 14.2
One feature of Swift that is truly confusing at first is how the behaviors of its classes and structs differ when they are copied: copies of the same class share their underlying data, meaning that changing one changes them all, whereas structs always have their own unique data, and changing a copy does not affect the others.
The technical term for this distinction is “value types vs reference types.” Structs are value types, which means they hold simple values such as the number 5 or the string “hello”. It doesn’t matter how many properties or methods your struct has, it’s still considered one simple value like a number. On the other hand, classes are reference types, which means they refer to a value somewhere else.
For value types, this is easy enough to understand that it’s self-evident. For example, look at this code:
var message = "Welcome"
var greeting = message
greeting = "Hello"
When that code runs, message
will still be set to “Welcome”, but greeting
will be set to “Hello”. As Chris Eidhof says, “this is so natural it seems like stating the obvious.” (https://chris.eidhof.nl/post/structs-and-mutation-in-swift/) But that’s how structs behave: their value are wholly contained inside their variable, and not somehow shared with other values. This means all their data is stored directly in each variable, so when you copy it you get a deep copy of all the data.
In contrast, the best way to think about a reference type is that it’s like a signpost pointing to some data. If we create an instance of a class, it will take up some memory on your iPhone, and the variable that stores the instance is really just a signpost to the actual memory where the object lives. If you take a copy of the object, you get a new signpost but it still points to the memory where the original object lives. This is why changing one instance of a class changes them all: all copies of the object are signposts pointing to the same piece of memory.
It’s hard to overestimate how important this difference is in Swift development. Previously I mentioned that Swift developers prefer to use structs for their custom types, and this copy behavior is a big reason. Imagine if you had a big app and wanted to share a User
object in various places – what would happen if one of those places changed your user? If you were using a class, all the other places that used your user would have their data changed without realizing it, and you might end up with problems. But if you were using a struct, every part of your app has its own copy of the data and it can’t be changed by surprise.
As with many things in programming, the choices you make should help convey a little of your reasoning. In this case, using a class rather than a struct sends a strong message that you want the data to be shared somehow, rather than having lots of distinct copies.
SPONSORED From March 20th to 26th, you can join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer!
Sponsor Hacking with Swift and reach the world's largest Swift community!
Link copied to your pasteboard.