Swift version: 5.6
It’s the job of a regular Swift initializer to create a fully fledged instance of a new type, however sometimes the data that has been provided is insufficient or incorrect, and creation can’t proceed.
For example, consider this code:
struct Person {
var ssn: String
init(socialSecurityNumber: String) {
self.ssn = socialSecurityNumber
}
}
let person = Person(socialSecurityNumber: "111-11-1111")
print(person)
That defines a Person
struct that can be created using a nine-digit social security number, then creates an instance of that struct.
But what should happen here?
let person = Person(socialSecurityNumber: "FISH")
In that instance we’re passing an invalid social security number, so really we expect creating a Person
to fail.
This is where failable initializers come in: they are written as init?()
, and can return nil rather than a value if something goes wrong during creation. For example, we could write a quick check to make sure the social security number is more or less correct like this:
struct Person {
var ssn: String
init?(socialSecurityNumber: String) {
if socialSecurityNumber.count < 11 {
return nil
} else {
self.ssn = socialSecurityNumber
}
}
}
Notice the initializer is now called init?()
to reflect that it returns an optional – the process might return nil
if the creation fails. The logic is pretty simple: if there are 11 digits we assume it’s correct, otherwise we return nil. Note: if you really wanted to validate that number you’d need to use a regular expression.
SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.
Sponsor Hacking with Swift and reach the world's largest Swift community!
Available from iOS 8.0 – learn more in my book Swift Design Patterns
This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.
Link copied to your pasteboard.