UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

How to work with Variables inside Classes

Forums > 100 Days of SwiftUI

Hi all. I'm having trouble understanding this lecture and it was quite confusing to me so I did some additional searching and tried to create a "documentation" by adding comments so that I can understand things better. I'm not sure if my understanding is now completely correct which is why I was hoping that someone could help validate if my understanding is in line with what Paul is trying to convey.

Note: ARC is also new to me and I don't know it that well yet but from my understanding, it just cleans up the memory in Swift (don't know why or how; Don't know what this achieves but I'm guessing it's just to make our code run faster?)

class UserExampleVarClass {
    var name = "Paul"
}

var userExampleVarClass =  UserExampleVarClass()

// In the code below, we're changing the value of a variable within an instance of UserExampleVarClass
userExampleVarClass.name = "Taylor"

// Here, we'll be changing the actual whole instance of our UserExampleVarClass
// We're saying here that userExampleVarClass is a whole new UserExampleVarClass
// Basically, we're reassigning userExampleVarClass to a new instance of UserExampleVarClass
// This effectively discards the previous instance and creates a new one
userExampleVarClass = UserExampleVarClass()

// The code below still printed out "Paul" because even though we overwrote our UserExampleVarClass
// and changed the name to "Taylor", we still pointed the class to somewhere else. This is why it worked.
// if we said let userExampleVarClass = UserExampleVarClass(), this wouldn't work because userExampleVarClass
// is now a constant. However, since it's a variable, you can think of it as creating two separate instances.
// One instance contains "Paul", while another instance contains "Taylor".
// We then just point to whichever instance of the class we want to.
// Despite changing the name to "Taylor" earlier, the code below still prints "Paul"
// This is because we created a new instance of UserExampleVarClass when we reassigned
// userExampleVarClass to a new instance. The new instance's name property is "Paul".
print(userExampleVarClass.name)

// To sum everything up, here's what we did:
// 1. We created an instance of our UserExampleVarClass by creating a new variable named userExampleVarClass and assigning the existing class to it (var exampleVarClass = ExampleVarClass())

// 2. In our created instance, we changed the variable name inside our class from Paul to Taylor. This means that our instance (userExampleVarClass) now inherits every property that we have from our class except we've decided to change/overwrite the name which is why it now holds Taylor instead of Paul.

// 3. We then created a new instance of the class and assigned it to the same variable. The new instance now has all of our original default property values because it's a fresh instance of the class. The previous instance, with the edited property, now becomes unreachable and will eventually be deallocated by ARC (Automatic Reference Counting).

// 4. When we now try to print userExampleVarClass.name, it yields Paul. This is because we re-assigned it back to the "default" initialized properties that our class has. This means that "Taylor" is no longer accessible since we lost the reference to it (which happened because we re-assigned it).

// 5. Taylor, although inaccessible is still stored in Swift's memory. However, it will also be eventually deleted by Swift's memory management called Automatic Reference Counting (ARC).

//In essence you could also think of it as creating an instance, changing the property value of an instance, once you're done with the edited property, you wanted to still use that instance but revert every single property back to its original state hence, reassigning it. (This also means that you no longer have any access to the edited property variables once it's re-assigned back to the original state).

// Four possible situations:
// 1. Constant class and constant property - we can't change anything
// 2. Constant class and variable property - let instanceOfAClass = Class(); class contains var properties
// 3. Variable class and constant property - var instanceOfAClass = Class(); class contains let properties
// 4. Variable class and variable property - var instanceOfAClass = Class(); class contains var properties

// Note and remember that classes are different from structs.
// structs CANNOT have their properties changed even if
// the properties are initialized using "var" and not "let"
// Changing a var property in our struct, would also change the default initialized var of the struct

Apologies for the huge block of comments but I hope someone could help validate my understanding and correct me if my understanding of the lecture was wrong.

1      

ARC is also new to me and I don't know it that well yet but from my understanding, it just cleans up the memory in Swift (don't know why or how; Don't know what this achieves but I'm guessing it's just to make our code run faster?)

ARC's an approach to automating when memory is released. Basically, whenever you refer to a variable in a new place, it increases the number of times it's been seen by 1. Then, if that place that called it, it's memory is released, the count goes down by 1. If the count goes to zero, then it can free the variable because nothing is relying on it being there.

There are more wrinkles than that, but that's the most basic explanation. Essentially, it eliminates crashes caused by oddball errors where things got deleted that shouldn't have.

Your summary of the four kinds is correct, but struct isn't quite correct:

struct Name {
    let name1: String
    var name2: String
}

let letName = Name(name1: "Amir", name2: "Pedro")
letName.name1 = "Ann"   // error, `name1` is a `let` constant
letName.name2 = "Valerie"   // error, `letName` (not `name2`) is a `let` constant

var varName = Name(name1: "Amir", name2: "Pedro")
varName.name1 = "Ann"       // error, `name1` is a `let` constant
varName.name2 = "Valerie"   // works

This ultimately gets down to whether the memory is allocated on the stack (struct, enum) or heap (class, closure). Stack is faster, but heap is more flexible.

I really like the explanation from the very odd book _Why's Poignant Guide to Ruby:

Some parts of your program are like little houses. You walk in and they have their own variables. In one house, you may have a dad that represents Archie, a traveling salesman and skeleton collector. In another house, dad could represent Peter, a lion tamer with a great love for flannel. Each house has its own meaning for dad.

So if you think of one class/struct instance as one house on a block, and another instance as a different house on the block, the lesson may be clearer.

Does that help at all?

1      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.