What is "self", "Self", and ".self" in Swift?

·

3 min read

The "self" keyword is a way to refer to an instance of a type (struct, class, and enum) within its own methods or initializers, similar to "self" in Python. However, we also see the uppercase "Self" and with the "." prefix pattern ".self". What is the difference? Today, I will explain how to use these three variations of "self".

self

The lowercase "self" is, as mentioned above, is used to refer to the current instance of a type within its own methods or initializers. It is used to disambiguate between a type's property and a method parameter or local variable with the same name. Here is an example:

class Person {
    let name: String

    init(name: String) {
        self.name = name
    }

    func greeting {
        print("Hi, I'm \(self.name).")
    }
}

let person = Person(name: "Steve Jobs")
person.greeting() // Output: Hi, I'm Steve Jobs.

In this example, "self.name" refers to the "name" property of the "Person" instance, distinguishing it from the "name" parameter of the initializer. It is important to note that "self" refers to the instance itself, not the property. Only when "self" is followed by the dot "." and the property name ("name" in this case), it refers to the property.
In most cases, because the names of parameters of initializers are the same as the names of properties, "self" is necessary to differentiate between them.

Self

On the other hand, "Self" refers to the type itself within a type's definition. Static properties are strongly connected to type, so it is often used in static contexts. In a case when a method return an instance of the same type, it is also used. Let's see an example:

class Person {
    let name: String
    static let species = "Homo sapiens"
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func celebrateBirthday() -> Self {
        let newAge = age + 1
        return Person(name: name, age: newAge)
    }

    func greeting {
        print("Hi, I'm \(self.name). I'm a \(Self.species).")
    }
}

let person = Person(name: "Steve Jobs", age: 40)
person.greeting() // Output: Hi, I'm Steve Jobs. I'm a Homo sapiens.

let newPerson = person.celebrateBirthday() // newPerson is 41-age Steve Jobs

In this example, "Self.species" refers to the static property "species" of the "Person" type itself, rather than an instance of "Person".

.self

We often see "\.self" in the context of SwiftUI.
".self" is a key path that specify an object itself, and the backslash "\" is the prefix to indicate that it is a key path.

Then, why is it commonly used in SwiftUI?

In SwiftUI, it is necessary for each "view" to be uniquely identifiable so that SwiftUI can efficiently update and animate the user interface. Using ".self" as an identifier is a way to satisfy this requirement. For example, when we use "ForEach" and "List" with a collection of views, ".self" can be used as the identifier because each element of the collection must be identifiable.

ForEach(0..<5, id: \.self) { number in
    Text("Number is \(number)")
}

By using ".self" as the identifier, each element in the range 0..<5 becomes uniquely identifiable, allowing SwiftUI to update and manage the views.