Class vs. Struct in Swift (copying)

Viewed 667

I am trying to understand the concept of why struct vs. class have difference results. Why is the result the same here but different on structs:

import UIKit

class Message {
    var internalText: String  = "This is some text"
}


// create new instance

var firstMessage = Message()

//if I assign, its a reference to the original instance
var secondMessage = firstMessage

secondMessage.internalText += " with some more text added on."

//print both
print(firstMessage.internalText)
print(secondMessage.internalText)

output:

This is some text with some more text added on.

This is some text with some more text added on.

Now if you change the above from declaration from "class" to "struct"

    struct Message {
        var internalText: String  = "This is some text"
    }
...

output becomes:

This is some text

This is some text with some more text added on.

Why in the class declaration does it change the firstMessage object. Are they the same objects? Is this a rule that if I assign a new object from the old object? Then I would have to declare secondMessage = Message() to make it a new instance. Thanks in advance.

6 Answers

In Swift, classes are reference types, whereas structs are value types. Value types are copied on variable assignment, whereas reference types are not.

More explanation

The system stores instantiated classes and structs into the memory. There are two main sections of the memory involved in the storage of data, the stack, and the heap. The stack contains the local variables introduced in the current method or function, and the heap is used as a kinda external memory, storing larger values. The program can only access variables stored in the stack, so a reference to the value in the heap should be held in the stack.

When you instantiate a class object by using something like Message(), a free space is reserved in your memory's heap and a reference to it is held in the stack. When you assign the same variable to a new one, the reference is copied and both variables will refer to the same bytes in the heap, so changing one changes another too.

When using structs, all the space is being reserved on the stack and there is no such thing as a pointer or reference, so when assigning to a new variable, all the data gets copied (in fact, the system is smart enough to only copy the necessary values which are being changed).

You can see a nice tutorial covering these subjects here.

Let us understand the same concept with an example, Suppose you have a google sheet in which you are adding some text and at a time you share that sheet to some other person for editing or deleting purpose. So when the other person do any changes you can see at a time. This concept is followed in class. Moreover, classes are reference types because here you are passing a reference(sheet).

However, you have downloaded that google sheet and send its copy to another person so at that time you are not able to see the changes until and unless the person sends back the sheet. And this is the same concept followed in struct. A struct is value type because we are passing a copy(downloaded sheet).

We can inherit class but cannot inherit struct

Classes are reference types, meaning that the firstMessage and secondMessage variables you defined in your first snippet stores only a reference to the class instance you created. Imagine your object is located somewhere in your memory heap with an id (for example, id0001), then both firstMessage and secondMessage stores only the id, which is id0001, so they both refer to the same object in memory.

On the other hand, structs are value types, meaning that the struct variables store unique objects directly; unlike reference types, no sharing is going on. So when you are assigning a new struct variable to a previous struct variable, the object gets copied, and the two variables store two unique objects with different memory addresses (IDs).

For more information, check out the official doc on classes and structs.

Simple answer: Classes are reference types Structs are value types.

In the class, firstMessage is set to Message() which is an instance of the whole class Message. So when secondMessage gets set to equal firstMessage, secondMessage Doesn’t make a new class again, it just makes a note of where firstMessage is at and they both can now operate it. But because they both in the same location, the internalText will be the same for both.

While with the struct, since they are value types, secondMessage copies all the values from firstMessage and creates its own independent object of type Message.

Why in the class declaration does it change the firstMessage object. Are they the same objects?

The example you gave is a really nice one because it succinctly illustrates the difference between class and struct, and you came about this close -> <- to answering your own question, even if you didn't realize it. As the other answers have explained, class creates a reference type, which means that when you assign an instance of a class to a variable, that variable gets a reference to the object, not a copy of it. You said so yourself:

//if I assign, its a reference to the original instance
var secondMessage = firstMessage

In your example, firstMessage and secondMessage are really references to the one object that you created. This kind of thing is done all the time in object oriented languages because it's often important to know that you're dealing with a specific object and not a copy, especially if you might want to make changes to that object. But that also brings danger: if your code can get a reference to an object and change it, so can some other code in the program. Shared objects that can be changed create all kinds of headaches when you start writing multithreaded code. When you added text to secondMessage, firstMessage also changed because both variables refer to the same object.

Changing the declaration of Message to struct makes it a value type, where assignment (for example) creates a new copy of the object in question instead of a new reference to the same object. When you added text to secondMessage after changing Message to a struct, the assignment secondMessage = firstMessage created a copy of firstMessage, and you only changed that copy.

Is this a rule that if I assign a new object from the old object?

Whether your assignment creates a copy of the object or a reference to it depends, as you've shown, on whether the thing being assigned has reference semantics (class) or value semantics (struct). So you need to be aware of the difference, but most of the time you don't need to think too hard about it. If you're dealing with an object where you don't care about the object's identity and are mainly concerned with its contents (like a number, string, or array), expect that to be a struct. If you care about which object you're dealing with, like the front window or the current document, that'll be a class.

Then I would have to declare secondMessage = Message() to make it a new instance.

Right -- if Message is a class, assigning one to a new variable or passing it into a method won't create a new one. So again, are you more likely to care about which message you're dealing with, or what is in the message?

Think of structs as a Microsoft Excel file. You create a copy and send it to me. When I change my copy, your copy doesn't get changed.

Classes on the other hand are more like Google Sheets. When I make changes to the file you shared with me, you can see the changes.

  • Instances of structs make copies and have different places in memory
  • Instances of classes point to the same place in memory
Related