self vs Self in Swift

self vs Self in Swift

In Swift, "self" and "Self" have different meanings and contexts.

  • "self" refers to the current instance (value) of a class or structure.
  • "Self" refers to the current type of the instance, primarily used within protocols.
💡
self could hold values like 23, "Hello WOrLd" or false
Self could hold type of instance like Int, Bool or String

self (lowercase):

  • In Swift, "self" with a lowercase 's' refers to the current instance of a class or structure within its own instance methods or properties.
  • It's used to distinguish between instance variables and method parameters that have the same name.

self in code example:

class MyClass {
    var value: Int
    
    init(value: Int) {
        self.value = value // 'self' is used to refer to the instance variable 'value'
    }
    
    func printValue() {
        print(self.value) // 'self' is used to access the instance variable 'value'
    }
}

This code snippet defines a class MyClass with an instance variable value, an initializer init(value:), and a method printValue().

  • Inside the init(value:) initializer, self.value refers to the instance variable value, and value refers to the parameter passed to the initializer. Using self distinguishes between the instance variable and the parameter.
  • In the printValue() method, self.value is used to access the instance variable value.

This usage of self is standard in Swift to disambiguate between instance variables and local variables or parameters within the same scope. It's a common practice to use self explicitly in initializers and methods, though in many cases, it's optional because Swift can infer the context.

Self (uppercase):

  • "Self" with an uppercase 'S' is used to refer to the type of the current instance. It's primarily used within protocols to refer to the conforming type.
  • It allows for better clarity in cases where the exact type is ambiguous or when referring to static members or methods.

Self in code example:

protocol MyProtocol {
    static func createInstance() -> Self
}

class MyClass: MyProtocol {
    required init() {}
    
    static func createInstance() -> Self {
        return self.init() // 'Self' is used to return an instance of the conforming type
    }
}
  • We've declared a protocol called MyProtocol with a static method createInstance(), which returns an instance of the conforming type (Self).
  • We've defined a class MyClass that conforms to MyProtocol.
  • The required initializer ensures that any subclass of MyClass also implements this initializer.
  • Inside the createInstance() method of MyClass, Self is used to indicate that the method should return an instance of the same type that conforms to MyProtocol.
  • Finally, self.init() is used to create and return a new instance of MyClass.

This pattern allows MyClass or any subclass of MyClass to adhere to MyProtocol and provide a way to create instances of themselves using the createInstance() method.