September 25th 2020
By Adin Cebic, iOS Developer at Klika
To get started
Swift and other programing languages give us the ability to initialize a variable or constant with a literal value. While that may seem like something built into compiler and inaccessible to you, it is actually fairly simple in Swift due to it's protocol oriented nature. Behind the scenes, whenever you create a variable
var number = 2
Swift calls integer initializer to construct that integer structure for you and infers that it is Int indeed.
Let's see how to extend Swift literals to provide extra functionality.
To make a type conform to ExpressibleByIntegerLiteral protocol, there is only one initializer that needs to be overridden init(integerLiteral value: IntegerLiteralType).
To demonstrate the point, we are going to extend the Date type to make it possible to create dates from integers, so start by making an extension on Date and making it to conform to ExpressibleByIntegerLiteral
Xcode will immediately start nudging you to add protocol stubs, so I recommend implementing that required initializer I mentioned above
Now all that is left to do is to implement some custom logic that fits your needs, in this case, I am going to make a date out of integer
Yes, you can use underscores with integers, they are ignored.
Working with value objects
Before we begin, let me get the question about value objects out of the way. Value objects are custom types that are small, precise types that represent one piece of our application. Like value types value objects should be both immutable and equatable, but they also add in validation as part of their creation. This means that if you’re handed a value object you know for sure it’s already passed validation – you don’t need to re-validate it, because if it were invalid then it couldn’t exist.
Let's say that we are building banking app and that we have an IBAN number to validate. Now you may write an extension on String or build helper methods to make validating those IBAN numbers easier and you will be right. However, I propose value object for that task. To build a value object in Swift, all that is needed is to create a struct for our IBAN number and implementing failable initializer.
Notice the question mark in initialiser declaration, that allows us to return nil if our validation fails thus our IBAN object wont be created. Let's add some validation to our initializer and make it fail if our requirement is not met.
Here I assumed that IBAN needs to have "AT" as its country identifier and that it needs to be exactly 34 characters, failing to comply with these rules will result in getting back nil instead of IBAN object. To use it, you may write something like this
One of the most common complains about value objects is that they are a pain to create because you need to specify the type. To solve that, we are going to utilize ExpressibleByStringLiteral to make it a bit nicer.
Now you are able to call "sendMoney" method like this
Unfortunately we lose the failability of value object since we crash if our validation fails. However, maybe think about using this in your test target only and use failable initializer in your production code.
Of course, you can express many literals besides strings and integers, I suggest you take a look at Apple's documentation on initialization with literals HERE
If you are curious about value object, you can research about domain driven design.
I hope you find these two techniques interesting and that you are going to find proper uses for them in your projects.