Custom initializers in Swift

Custom initializers have always been a staple of Cocoa, in Objective-C the pattern would look like this:

- (id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName {
  self = [super init];
  if (self) {
    self.firstName = firstName;
    self.lastName = lastName;
  }
  return self;
}

A custom initializer saves you time and also helps you follow the MVC design pattern by allowing your model classes to encapsulate the logic needed to initialize and configure an object with some initial property values passed in as arguments, rather than returning a generic object that still needs to have its properties set before it's actually useful, like this:

// Using the default initializer
Person *person = [[Person alloc] init];
person.firstName = @"John"
person.lastName = @"Clem"
// Using our custom initializer
Person *person = [[Person alloc] initWithFirstName:@"John" lastName:@"Clem"];

Swift brings a ton of new language features and design patterns, initializers are not a new concept, but for Objective-C developers, it's important to know A) how they work and B) how they work differently than Objective-C.  Let's take a look at the most simple initializer in Swift:

init() {}

Ok, I know. Not very exciting huh?  Default initializers functions are implied, so coding the simple init function above in our Person class doesn't do anything right off the bat, so let's take a look at how to write a designated initializer that takes some arguments, like the ObjC example above:

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

You'll probably notice some similarities to the ObjC example. Other than the syntax, the only real difference is that we never set self equal to [super init], or more accurately, super.init(). Initializers can choose to call super.init() if necessary, which is particularly useful in subclasses, and you can have as many designated initializers as you want (see overloads), but in Swift, you can actually write a class without any initializers and it'll compile and run just fine.  

How can this be? Swift will use your initializers if you provide them, but intelligently and safely handles initialization with a 4-step safety check process for initializing an object (see Initializer Chaining in The Swift Programming Language iBook.  It's definitely worth a read).

For our Person class, we might write a couple Designated initializers like this:

    init() {
        self.image = UIImage(named: "placeholder_image.png")
    }
    init(firstName : String, lastName : String) {
        self.firstName = firstName
        self.lastName = lastName
    }

The first init method sets our placeholder image for a new Person, the second takes two strings for the first and last name, then sets them on the new Person object.  To create a new Person object we just need to call the appropriate designated initializer: 

var newPerson = Person(firstName : "John", lastName : "Clem")

When we get our newPerson object back from the line of code above, it will have its firstName and lastName variables set using the strings we passed in, but the interesting (and incredibly cool) part is that the newPerson object will also have the placeholder image set.


To round things out, let's take a quick peek at Convenience Initializers.  Convenience Initializers are exactly what they sound like, just a convenient way to initialize a new object in your code.  Note that if you're following along in Xcode, you'll get a warning that you've redefined init(), simply comment out your existing init() function then try the following Convenience Initializer:

convenience init() {
  self.init(firstName: "Given Name", lastName: "Surname")
  self.image = UIImage(named: "Photo-Video-slr-camera-icon")
}

Our team is working hard to learn Swift, and we plan to blog, teach and share our code along the way, because for the first time in most of our lives as Cocoa developers, we all get to start at square one together.

The code samples above are from the Class Roster app that myself (John Clem), Brad Johnson, Taylor Potter and Reed Sweeney are all working on as part of a month long experiment to re-write all of our iOS teaching curriculum in Swift, so be prepared for some errors and some incorrect assertions, and please join the conversation by leaving a comment, submitting some code samples or writing a post for the site.

You can find the project that the above code snippets were excerpted from on Github