Failable initialisers in Swift, and their usage

Savita Agrawal
Evangelist Apps Blog
3 min readMar 6, 2023

Failable initialisers are initialisers which may fail to initialise the resource needed for a class or a structure, thereby rendering the instance unusable. When using the Failable initialiser the result of the initialiser is an optional type, containing an either valid instance of the type or nil if it fails to init.

In custom initialisation, we do not need to include a return statement as Swift does not need a return to the initialised instance. However in a Failable initialiser if the initialisation fails it will return nil. If the initialiser successfully initialises the object we do not need to return anything.

How to create:
Failable initialiser is created by adding a question mark (?) after the init keyword.

Here are a few use cases for Failable initialisers:

  1. When validation of user input is required in a Signing option with a user name and password against any empty parameter, we can use a failable initializer.
// Validating user inputs

struct LoginForm {
let username: String
let password: String

init?(username: String, password: String) {
guard !username.isEmpty, !password.isEmpty else {
return nil
}

self.username = username
self.password = password
}
}

func login() {
if let loginForm = LoginForm(username: "Evangelist", password: "") {
print("login username = ", loginForm.username)
} else {
print("failed to initialize")
}
}

2. These are used for a URL struct that checks if the URL string is valid

struct URL {
let urlString: String

init?(urlString: String) {
guard let url = Foundation.URL(string: urlString) else {
return nil
}
self.urlString = url.absoluteString
}
}

3. Failable initializer for a Temperature struct that checks if the temperature value is below absolute zero

struct Temperature {
let value: Double

init?(value: Double) {
guard value >= -273.15 else {
return nil
}
self.value = value
}
}

4. Failable initializers eliminate the most common reason for factory methods in Swift, which were previously the only way to report failure when constructing this object. For example, enums that have a raw type provided a factory method fromRaw that returned an optional enum. Now, the Swift compiler synthesizes a failable initializer that takes a raw value and attempts to map it to one of the enum cases. For example:

enum Color : Int {
case Red = 0, Green = 1, Blue = 2

// implicitly synthesized
var rawValue: Int { /* returns raw value for current case */ }

// implicitly synthesized
init?(rawValue: Int) {
switch rawValue {
case 0: self = .Red
case 1: self = .Green
case 2: self = .Blue
default: return nil
}
}
}

In this example, the Color enum has a failable initializer that takes in a rawValue of type Int. If the raw value does not match any of the cases defined in the enum, the initializer returns nil, indicating that the initialization failed.

Using the failable initializer allows greater use of Swift’s uniform construction syntax, which simplifies the language by eliminating the confusion and duplication between initializers and factory methods. Along with the introduction of failable initializers, Swift now treats more Cocoa factory methods — those with NSError arguments — as initializers, providing a more uniform experience for object construction.

Thanks for reading!

Please follow us on Twitter and LinkedIn for more updates.

#iOS #SwiftUI #Swift #FailableInitializer

--

--

Savita Agrawal
Evangelist Apps Blog

I'm an iOS Developer and my passion is developing iOS, iPhone and tvOS apps. I'm proficient in C, C++, ObjC and Swift. I enjoy blogging, writting and reading.