Software, Tech & Coding simplified.

“self” in Swift

In Swift, the self keyword refers to the object itself. It is used inside the class/structure to modify the properties of the object. You can assign initial values to properties in the init() method via self.

For instance:

class Fruit {
    let name: String
    let color: String

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

In this guide, you learn what is self and when you should/should not use it. In addition, we are going to take a look at the Self keyword (with capital “S”) and the .self property at the end.

The “self” Keyword in Swift

In Swift, the self keyword refers to the current object inside the type that implements the object.

The self keyword is available within:

The self keyword is usually not required. The only times you should use self is:

  1. To differentiate a property from a local variable that has the same name.
  2. Reference a property inside a closure.
  3. Reference to the enumeration cases inside an enumeration.
  4. To refer properties inside extensions.

Let’s take a look at the examples of when using self is necessary.

Differentiate Property Names from Argument Names in the init() Method

The self keyword is required when initializing a type with arguments that have the same name as the properties:

class Fruit {
    let name: String
    let color: String

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

But why is this?

Let’s leave out the self keywords from the above piece of code:

class Fruit {
    let name: String
    let color: String

    init(name: String, color: String) {
        name = name
        color = color
    }
}

As you can see, now it says name = name and color = color. This introduces ambiguity into the code. We do not know which name refers to the argument passed into the init() function and which one to the name property. This is why Swift requires using the self keyword to access the properties in the initializer.

By the way, if you change the names of the init() arguments to be something different than the names of the properties, you can get rid of using self.

For example:

class Fruit {
    let name: String
    let color: String

    init(n: String, c: String) {
        name = n
        color = c
    }
}

Now there is no need to write self.name or self.color. Swift knows you refer to the property because the init() arguments have different names.

However, it is common to keep the names of the init() arguments the same as the names of the properties and use self!

Reference Properties in a Closure Using self

If you have a closure in the type, and you want to access a property, you need to use the self keyword.

For instance, let’s add an info() closure into the Fruit class:

class Fruit {
    var name: String
    var color: String

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

    var info: () -> (String) {
        return {
            "\(self.name) + \(self.color)"
        }
    }
}

But why do we have to explicitly state self in a closure and not in a regular function?

This is because Swift wants you to acknowledge that using the object (self) in a closure can lead to retain cycles. In other words, the object (self) will not be deallocated before the closure is deallocated. To truly understand what this means and how to avoid it, check out this article.

And yes, the Swift compiler could easily infer self in the closure context. But using self is done to keep the developer aware of the possible issues it may lead to.

Enumeration Cases and self in Swift

To perform an action inside enum in Swift based on the enumeration case, you can use a switch statement on self.

For instance:

enum Direction {
    case North
    case East
    case South
    case West

    func info() -> String {
        switch self {
            case .North:
                return "Going North"
            case .East:
                return "Going East"
            case .South:
                return "Going South"
            case .West:
                return "Going West"
        }    
    }
}

let dir = Direction.North
print(dir.info())

Output:

Going North

The info() function has a switch statement that compares the current instance of the enumeration with each enumeration case. This is possible via self.

Extensions and self in Swift

If you write an extension to a type in Swift, use self to perform an action on the instance of the type.

For example, let’s write a squared() extension to the Int type. To square an integer object, the integer object must multiply itself by itself:

extension Int {
    func squared() -> Int {
        return self * self
    }
}

Now you can square an integer by calling the squared() method on an integer object:

let n = 10
let s = n.squared()
print(s)

Output:

100

Now you know what the self keyword means in Swift and how to use it.

Last but not least, let’s have a look at other “selfs” in Swift, that is, the Self in protocols and the .self property for types.

Self with Capital “S” in Swift

In Swift, there is a self-related reserved keyword called Self with capital “s”.

The Self keyword is used in protocols to represent the type that is going to conform to the protocol.

For instance:

protocol Callable {
    func greet(_ other: Self)
}

struct Person : Callable {
    func greet(_ other: Person) {
        print("Hi, I am  \(other)")
    }
}

The Callable protocol requires that any custom type conforming to it must implement the greet method. However, as there is no way to tell the names of the types that are going to conform to Callable in the future, there has to be another way to reference them. This is where the Self keyword is used. In the Person struct, the Person replaces the Self from the Callable protocol in the greet method argument type.

Self in Swift Protocols
Self refers to the type that conforms to the protocol later in the code

The .self in Swift

In addition to self and Self, there is a “third self” in Swift, the .self property of a type.

The .self is used to access a type as a value.

For example:

Int.self

This returns the Int itself, not an instance of an Int.

Another way to access the type as a value is by using the type(of:) function.

Let’s see an example:

struct Fruit {
    var name = "Banana"
}

let fruit = Fruit()
type(of: fruit) == Fruit.self // Returns true

Conclusion

Today you learned what self, Self, and .self mean in Swift.

To recap:

  • self refers to the object itself. You can access the properties of an object via the self in the type.
  • Self refers to a type that conforms to a protocol in the future.
  • .self refers to a whole type as a value.

Out of the “three selves” you are going to use self the most. It is used in the class/struct init() method to assign initial values to the properties. Also, you are going to need self in closures, extensions, and enumerations.

Thanks for reading.

Happy coding!

Further Reading

All reserved keywords in Swift

50 Swift Interview Questions

Share

Share on twitter
Share on linkedin
Share on facebook
Share on pinterest
Share on email