What is "self", "Self", and ".self" in Swift?
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.