Memberwise Initializers for Structure Types

Swift Initialization Struct

Struct is one of the basic building blocks in your app. Today I'm going to share some tips about memberwise Initializers.

Default Memberwise Initializers #

If you don't define any custom initializers on your struct, it will automatically receive memberwise initializer. The memberwise initializer contains all the members of that struct.

If you declare your Struct like this:

struct User {
let firstName: String
let middleName: String?
let lastName: String
}

Without the need to declare init, you can initialize it like this:

let user = User(firstName: "John", middleName: nil, lastName: "Doe")

You get this for free, and this might suit your needs most of the time.

Not all member creates equal #

There might be a time where you don't need every property to be set (middleName in this case), you may want something like this:

let user = User(firstName: "John", lastName: "Doe")

Too bad you will get this error:

Missing argument for parameter 'middleName' in call

Missing argument error

There are many ways to tackle this problem.

Default Parameter Values #

The first one is using one feature of Swift Fuction, Default Parameter Values.

From Swift Document:

You can define a default value for any parameter in a function by assigning a value to the parameter after that parameter’s type. If a default value is defined, you can omit that parameter when calling the function.

You declare .init and define a default value to a parameter you want to omit. I want to omit middleName in this case, so I set the default value to nil.

struct User {
let firstName: String
let middleName: String?
let lastName: String

init(firstName: String, middleName: String? = nil, lastName: String) {
self.firstName = firstName
self.middleName = middleName
self.lastName = lastName
}
}

Try to initialize User object again, and the error is gone.

let user = User(firstName: "John", middleName: "D", lastName: "Doe")
let user = User(firstName: "John", lastName: "Doe")

The downside of this method is you have to create a custom initializer for your struct and lose all the benefit of the memberwise initializer. You have to type every property in the struct in your custom initializer. This can be tiresome, so here come the second solution.

Default Property Values #

In Swift 5.1, you can set default value into a property, and memberwise initializer will be generated with a default parameter set. Just like the one we manually did in the previous solution.

struct User {
let firstName: String
var middleName: String? = nil
let lastName: String
}

Define a default value for a property like this would generate the following memberwise initializer.

// The generated memberwise init:
init(firstName: String, middleName: String? = nil, lastName: String) {
self.firstName = firstName
self.middleName = middleName
self.lastName = lastName
}

This will save you a lot of keystrokes if you have a lot of properties. The only difference here is you have to declare middleName as var instead of let.

But, I want it to be let #

If you want your middle name to be let (It doesn't change that often right?), you have no choice other than using Default Parameter Values. To save some keystroke, you can use Xcode "Generate memberwise initializer" shortcut.

⌘ - command + click (based on your preference, it might be ⌃ – Control + ⌘ - command + click) on your struct and select Generate memberwise initializer.

Generate memberwise initializer
Generate memberwise initializer

or

Click on your struct, then Editor Menu > Refactor > Generate memberwise initializer.

or

Right-click on your struct, then Refactor > Generate memberwise initializer.

Generate memberwise initializer
Generate memberwise initializer

And you will get this without any typing.

Generated memberwise initializer
Generated memberwise initializer

The only thing you need to do is change the scope and assign a default value to middleName parameter.

struct User {
init(firstName: String, middleName: String? = nil, lastName: String) {
self.firstName = firstName
self.middleName = middleName
self.lastName = lastName
}

let firstName: String
let middleName: String?
let lastName: String
}

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Tweet Share

If you enjoy this article, you can subscribe to the weekly newsletter.

Every Friday, you’ll get a quick recap of all articles and tips posted on this site — entirely for free.

← Home