Blog Detail

Swift Initializers

22 Jan 16
Steven Beyers
No Comments
Swift is full of exciting features and it certainly takes a long time of in-depth use to find them all and to build a true appreciation for them. Recently, I have been working with initializers and have found some new tricks, provided by Swift, that have simplified my work. I’m going to focus on Swift 2.1 and share some of the things that have helped me with initializers.

Initializers are one of the most basic functions of any programming language. After all, every object or struct that you use must be initialized! However, it is very easy to just use the generic init() method that every NSObject inherits. With Swift variables that are non-optional this leads to people frequently making one of two options. The first, initializing the non-optional variables with defaults, which does not work in every situation. For example, take the classic programming example of a car object. A make and model of the car is always required so they might be defaulted to an empty String. That does not really make sense, though, because that will never be valid. Second, many people mark the variable as a force unwrapped variable using the exclamation point (also known as “crash operator”). This would look something like var carModel: String!. This would work but it is error prone. If the car is accidentally created without ever assigning a model then the app will crash as soon as the carModel property is read. Here are a few ways to address problems like these.

I have prepared a sample app, Garage Keeper, to help demonstrate the points made in this post. The app can be found on GitHub. Garage Keeper will allow you to add all of the garages you have using a name (i.e. “Home Garage” or “Vacation House”) along with a capacity so that you know how many cars fit in that garage. The master branch is the starting point for this post.

Convenience Initializers

The first attempt that many people make at fixing a problem like this is to use convenience initializers. In the master branch of Garage Keeper if you look at the Garage class, this is exactly what was done. A convenience initializer was create that takes a name and capacity as the input parameters. It looks like this:

This works, but still leaves us with a problem. Since our new initializer is only a convenience initializer anyone can still create a Garage object by calling Garage() so then we must override the init() method and give default values for these properties. In the case of a garage, this option might not be too bad. the name doesn’t really matter so we can default the name to “default” and we can set the capacity to 1 by default so the garage can always hold at least 1 car. I still think this can be better.

Designated Initializers

By simply removing the convenience keyword from the convenience initializer we make it a designated initializer. That has some implications, however. In our convenience initializer for the Garage class we were first calling a designated initializer, self.init(), then assigning the non-optional values. In a designated initializer, however, the non-optional values must be set first. We must also call a designated initializer from the super class in this instance. Now, we can completely remove the plain override init() initializer from Garage and update our custom initializer to look like this:

This is must simpler and safer. The reason that it is safer is that we are now forcing everyone to create instances of Garage by using our custom initializer. We will not have any more “dummy” data to protect us from crashes. To view the updated class view the “designatedInitializers” branch on GitHub.

Failable Initializers

A “failable” initializer is an initializer that can, well, fail. That is to say that it will not be successful in initializing the object and will, therefore, return nil. Take a look at the AddGarageViewController file in Garage Keeper. In the save(_) method we are doing some validation before we create the Garage object. In this simple application that is the only way that we can create a Garage object. In most apps, however, objects can be created in many different ways. If this were the case for Garage Keeper, we would have to duplicate the the code everywhere that we create a Garage to make sure it never fails. By using a failable initializer, we can move all of that code into a centralized place. As an added benefit, we can have the Garage class handle validating the creation of a Garage instead of a UIViewController. Nothing makes more sense than that! To accomplish this the designated initializer in Garage will be modified to:

There are a few things going on here so I will explain. First, before we are allowed to return nil in an initializer, we must fully initialize all the variables. So, we start with giving a default name and capacity and call the super class’s designated initializer. This will fully initialize our object. These defaults are not quite the same as when we used the convenience initializer because they are guaranteed to be changed if all validation passes. Next, we make sure that the name and capacity that were passed in are not nil. If they are nil, initialization fails. The reason that we changed the inputs to be optional is to save other developers who want to initialize this class a little bit of time. Now, they will not even have to make sure they have a non-nil value before attempting to initialize a Garage. The third step is a check to make sure name is not empty. Previously, an empty String could have been passed in and that would have been acceptable. In fact, even with the code validation that we had in the view controller, this would happen if the user did not enter a name for the garage. Finally, after passing all validation, we store the passed in name and capacity in our object. At this point a valid Garage object will be created and returned.

There is still one last problem that can be fixed in this method. A garage is not a garage if it is not able to hold any cars. So, any numbers less than 1 for the capacity should be rejected. We can quickly fix this but adding the following code to our failable initializer:

Take a look at the failableInitializers branch on GitHub to see how AddGarageViewController was updated to take advantage of this. In summary, though, the save(_: AnyObject) method was changed to do no validation. Instead, it simply passes the values from the UITextFields to the Garage initializer. If nil comes back then an error alert is displayed and if a valid Garage is returned then it finishes processing successfully.

Required Initializers

Required Initializers are a special type of designated initializer. They work the same as designated initializers except for one important distinction. If you subclass a class with a required initializer you must override that initializer. This can be helpful when certain pieces of data are required to be passed in for every subclass. To demonstrate this, we added

to the Car object in Garage Keeper. Most often, we are dealing with normal cars so four wheels seems like a reasonable starting point. But what if I purchased a Polaris Slingshot? Thats a 3 wheel car. Of course, I could manually change that number but for this example I’m going to create a subclass of Car and name it UniqueCar. Now, I know that a Polaris Slingshot is a 3 wheeled car so I want to build that in. In this case i can override the required initializer in my new class. At that point I can check for the make and model that I want and if they match, I will automatically update the wheel count to 3. To do this I put the initializer in UniqueCar and make it look like this:

Then I just have to update UpdateCarViewController to use UniqueCar instead of Car. Of course, this is a silly example because I could have used the same code in the Car class and avoided a subclass but it shows that the required initializer is required in the subclass, which is why we use the required keyword instead of the override keyword. I should also note that removing the initializer from UniqueCar completely will still work fine because the implementation from Car will be inherited. Take a look at the requiredInitializers branch on GitHub to see how this was implemented in Garage Keeper.

I hope that this will help you in your efforts to write better, more simple code and increase code re-use in the future. If you want to learn more about initializers check out Apple’s documentation.