Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. SwiftBeginner - About Initializers (Constructors)

About Initializers (Constructors) - Images: Japanese

Hey there, everyone!

Continuing from last time, let's look at 'Initializers' — a follow-up to the classes and instances we covered before.

Simply put, an initializer is "a process that always runs when an instance is created."

This isn't unique to Swift — pretty much any language that supports classes has something like it. In other languages it's often called a constructor, and it works in a similar way.

Personally, calling an initializer a constructor is totally fine. Swift tends to use the term initializer, but different languages use different names for the same concept — so don't sweat the terminology too much.

Alright, let's jump right in and define a quick class. The class below does two simple things: assigns the string "Hatsune Miku" to a constant s, and then has a method m that prints it.

class Test {
    let s = "Hatsune Miku"

    func m() {
        print(s)
    }
}

Now that we've defined the class, let's run what's inside it. To do that we need to create an instance, so let's go ahead and do that. Then we'll call the method m on that instance.

class Test {
    let s = "Hatsune Miku"

    func m() {
        print(s)
    }
}

let testA = Test() // Creates an instance.

testA.m() // Prints "Hatsune Miku".

So far so good?

Let's do a quick recap of what we covered last time.

We said that a class is "like a blueprint." And because it's a blueprint, you can create as many instances from it as you like.

Take a look at the sample below. We've created a second instance called testB, also based on the class Test.

class Test {
    let s = "Hatsune Miku"

    func m() {
        print(s)
    }
}

let testA = Test() // Creates an instance.

testA.m() // Prints "Hatsune Miku".

let testB = Test() // Creates another instance.

This ability to create as many instances as you want is one of the powerful things about classes.

That said, looking at the sample above, there's not much point in creating multiple instances, right? They all just print "Hatsune Miku" — there's no difference between them.

class Test {
    let s = "Hatsune Miku"

    func m() {
        print(s)
    }
}

// The following all do the same thing, so there's not much point making multiple instances.
let testA = Test() // Creates an instance.

testA.m() // Prints "Hatsune Miku".

let testB = Test() // Creates another instance.

testA.m() // Prints "Hatsune Miku".

It would be a lot more useful if we could create instances in slightly different ways. Kind of like calling a function with different arguments to get different results.

func test(s: String) {
    print(s)
}

// Different arguments produce different results, like this.
test(s: "Hatsune Miku") // Prints "Hatsune Miku".
test(s: "Lily") // Prints "Lily".

That's where the 'initializer' comes in. An 'initializer' is a method (process) that always runs when an instance is created — which means we can use it to produce different instances each time.

Let's give it a try. Take a look at the sample below.

class Test {
    let s: String

    init() { // This is the 'initializer'.
        s = "Hatsune Miku"
    }

    func m() {
        print(s)
    }
}

Notice the init() {} part. That's the initializer.

The syntax looks like "a method (function) named init", so you write whatever you want to run inside {}, just like a regular function or method.

One thing to watch out for: do NOT write func in front of it, like func init() {}. That'll cause an error.

class Test {
    let s: String

    func init() { // Don't add 'func'. This will cause an error.
        s = "Hatsune Miku"
    }

    func m() {
        print(s)
    }
}

Also, you can't create a regular function or method named init — that'll get you an error too.

func init() { // You can't create a function named 'init'.

}

Now let's look inside the initializer. It says s = "Hatsune Miku", which means every time an instance is created, the constant s gets assigned "Hatsune Miku".

class Test {
    let s: String

    init() { // This is the 'initializer'.
        s = "Hatsune Miku"
    }

    func m() {
        print(s)
    }
}

let testA = Test() // Creates an instance.

testA.m() // Prints "Hatsune Miku".

let testB = Test() // Creates an instance.

testB.m() // Prints "Hatsune Miku".

We're using the initializer now, but both testA and testB still just print "Hatsune Miku". No difference yet.

Let's change the initializer so it accepts an argument and assigns that value to the constant s. Take a look at the code below.

class Test {
    let s: String

    init(str: String) { // The initializer accepts an argument.
        s = str
    }

    func m() {
        print(s)
    }
}

let testA = Test(str: "Hatsune Miku") // Creates an instance while passing an argument.

Look at the Test(str: "Hatsune Miku") part. Just like that, you can pass arguments inside the () when creating an instance, and those arguments are received by the initializer — in this case, at init(str: String). The argument syntax is the same as with regular functions.

With this setup, each instance can behave differently. Here's the complete version — you can see that we're now getting different results from each instance.

class Test {
    let s: String

    init(str: String) { // The initializer accepts an argument.
        s = str
    }

    func m() {
        print(s)
    }
}

let testA = Test(str: "Hatsune Miku") // Creates an instance while passing an argument.

testA.m() // Prints "Hatsune Miku".

let testB = Test(str: "Lily") // Creates an instance while passing an argument.

testB.m() // Prints "Lily".

When defining a class, the () for arguments does not go in class ClassName() {} — it goes in the initializer. This is easy to mix up, so be careful.

class Test() { // Don't put '()' here.

}

class Test {
    init() { // '()' goes in the initializer.
    }
}

In Swift, writing an initializer when defining a class is not required.

However, if a property (variable or constant) inside the class has no value assigned to it, the code won't compile. Take a look at the following.

class Test {
    var n: Int

    init() {
        n = 1
    }
}

Here, the class Test defines a variable n of type Int, and the initializer assigns 1 to it.

If you leave the init() {} body empty and don't assign anything to n, you'll get a compile error.

class Test { // Error.
    var n: Int

    init() {

    }
}
class Test { // Error.
    var n: Int
}

If you give the variable n a default value, there's no error.

class Test { // OK.
    var n: Int = 1 // Give it a default value.

    init() {

    }
}
class Test { // OK.
    var n: Int = 1 // Give it a default value.
}

A good rule of thumb to keep in mind: "if you're skipping the initializer, make sure every property in the class has a default value."

Initializers inside classes can use external argument names and be overloaded, just like functions and methods. Here's an example.

class TestA {
    let s: String

    init(miku _s: String) { // Using an external argument name.
        s = _s
    }

    func m() {
        print(s)
    }
}

let testA = TestA(miku: "Hatsune Miku") // Prints "Hatsune Miku".

testA.m() // Prints "Hatsune Miku".

class TestB {
    var n = 0, s = "Hatsune Miku"

    // The following 'init(){}' calls are overloaded.
    init(_n: Int) { // If the argument is '_n', this one runs.
        n = _n
    }

    init(_s: String) { // If the argument is '_s', this one runs.
        s = _s
    }

    func m() {
        print(n)
        print(s)
    }
}

let testB1 = TestB(_n: 10)

testB1.m() // Prints "10" and "Hatsune Miku".

let testB2 = TestB(_s: "Lily")

testB2.m() // Prints "0" and "Lily".

This pattern comes up quite often, so it's worth remembering.

* For more on external argument names, see this article.

* For more on overloading, see this article.

And that covers initializers!

In the next article, we'll look at the difference between functions and classes. See you there!

This article was written by Sakurama.

Author's beloved small mammal

桜舞 春人 Sakurama Haruto

A Tokyo-based programmer who has been creating various content since the ISDN era, with a bit of concern about his hair. A true long sleeper who generally feels unwell without at least 10 hours of sleep. His dream is to live a life where he can sleep as much as he wants. Loves games, sports, and music. Please share some hair with him.

If you find any errors or copyright issues, please .