In Objective-C, init method has no big difference from other normal methods except for returning self. If you like, you can even call it for multiple times (although you would never want to play so). Generally speaking, when the init method fails and the object cannot be initiated correctly, we will want to return a nil to inform the caller something goes wrong.

However, in early days of Swift, return statement cannot exist in an initializer, which means we have no chance to initiate an optional value. A good example would be initiating a url. In Objective-C, when we use a wrong string to initiate an NSURL object, a nil will be returned to indicate the init fails. So when passing the kind of typo string below (there is a space between two 't's and the dot seems strange) into a url init method, there will be no problem when compiling, but the result is nil:

NSURL *url = [[NSURL alloc] initWithString:@"ht tp://swifter。tips"];
NSLog(@"%@",url);
// Output: (null)

In Swift, things are a little different. The Objective-C -initWithString: is mapped to a convenience initializer in Swift: init(string URLString: String!). We can write the code above in Swift as:

let url = NSURL(string: "ht tp://swifter。tips")
print(url)

This will lead to totally different result in Swift 1.0 and 1.1, since the init method changes a lot in Swift 1.1. To make this clearer, we will see the results in both versions.

Swift 1.0 and earlier

If you run the code above in Swift 1.0 or earlier, you will get an EXC_BAD_INSTRUCTION, which means you trigger the Swift internal assertion. This initializer would not accept such input. A common workaround for this is using the factory pattern. Use a class method to generate and return an object. When it fails, return nil instead. In Swift 1.0, there is already such a factory method:

class func URLWithString(URLString: String!) -> Self!

Use it like this:

let url = NSURL.URLWithString("ht tp://swifter。tips")
print(url)
// Output: nil

If you really want to use the initializer instead of factory method, consider using an optional variable to store the result.

By doing this you can handle failed init as well, but with a higher complexity. swift let url: NSURL? = NSURL(string: "ht tp://swifter。tips") // nil

Swift 1.1 and later

Good news is Apple added failable initializers in Swift 1.1, which means we could return nil in init method as well now. Adding a ? or ! after the init word would change the initializers failable. In the situation which init process could not complete, just return a nil to indicate initiating failure.

For example, we can add an initializer to Int, let it accept a String and try to parse it to a number.

extension Int {
    init?(fromString: String) {
        if let i = fromString.toInt() {
            self = i
        } else {
            // Can not be converted to Int. Failed.
            return nil
        }
    }
}

let number = Int(fromString: "12")
// {Some 12}

let notNumber = Int(fromString: "XII")
// nil

Both number and notNumber are objects of Int? type. By applying optional binding, we can know if the init method succeeds or not. In this kind of failable init method, we can even assign self if it is a value type.

At the same time, factory methods like NSURL.URLWithString are not needed anymore from Swift 1.1. To simplify and make API safer, Apple marked these methods unavailable and they would cause a compiling error. Correspondingly, all initializers that might fail are added a question mark:

convenience init?(string URLString: String)

We should always use the failable initializers in new versions of Swift. Let's say farewell to the factory methods.