Swift type inference and UIColor convenience initialiser.
The Swift language and its type system incorporate a number of popular language features, including object-oriented programming via classes, function and operator overloading, subtyping, and constrained parametric polymorphism. Swift makes extensive use of type inference, allowing one to omit the types of many variables and expressions.
let count = 3 // type is inferred as `Int`
let name = "Vishal" // type is inferred as `String`
Type can also be inferred by the return type of the a function.
func countOfApples() -> Int {
return 10
}
let count = countOfApples() // type is inferred from the return type of `countOfApples` as `Int`
Struggle with UIColor
Lets say, we have an Objective C project. Our designer gave us r, g, b values for changing background to dark and light depending on user’s preference.
Dark RGB: (0, 0, 0)
Light RGB: (254, 248, 220)
Lets go ahead and implement dark background.
- (void)setDarkBackground {
[self.view setBackgroundColor: [UIColor colorWithRed:0/255 green:0/255 blue:0/255 alpha:1]];
}
Seems perfect, even though there is a mistake in the implementation. We will ignore it as everything is working fine as of now.
Now lets implement light background quickly.
- (void)setLightBackground {
[self.view setBackgroundColor: [UIColor colorWithRed:254/255 green:248/255 blue:220/255 alpha:1]];
}
Lets see how our light background looks.
Where is the light?
Debug
(UIColor *)colorWithRed:(CGFloat)red
green:(CGFloat)green
blue:(CGFloat)blue
alpha:(CGFloat)alpha
The method expects CGFloat
. Since, we quickly implemented light background, we forgot to add decimal in the r, g, b values. Objective C
can not infer that the result of the expression should be CGFloat
. The expression 254/255
returns result as NSInteger
which is 0
because in almost all languages, result of integer division is an integer. The method in setLightBackground
, therefore, is computed as:
- (void)setLightBackground {
[self.view setBackgroundColor: [UIColor colorWithRed:0 green:0 blue:0 alpha:1]]; //this is actually a black color.
}
To make sure it works correctly, we have to make sure that we add a decimal in the division expression so that it performs floating point division and returns correct value.
- (void)setLightBackground {
[self.view setBackgroundColor: [UIColor colorWithRed:254/255.0 green:248/255.0 blue:220/255.0 alpha:1]];
}
Using Swift type inference
In Swift
, we don’t need to pass in a decimal number and the type is inferred by the type of argument in the function. The same method which was causing issue in Objective C
, will give the desired result in Swift
. Since we are passing the result of the expression to a function which expects CGFloat
, the type is inferred as CGFloat
and it performs floating point division.
func setLightBackground() {
view.backgroundColor = UIColor(red: 254/255, green: 248/255, blue: 220/255, alpha: 1)
}
UIColor convenience initialiser
We still need to do the division by 255 while creating a UIColor
. Wouldn’t it be nice if we just need to pass the r, g, b values in the function to create a UIColor
.
I usually add below extension in my projects which makes creating UIColor
very convenient.
extension UIColor {
convenience init(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ alpha: CGFloat = 1) {
self.init(red: red/255, green: green/255, blue: blue/255, alpha: alpha)
}
}
The division is taken care by the implementation of the function. The value of alpha
is by default 1. We don’t need to pass the value of alpha
if its 1.
Usage of this convenience initialiser.
func setLightBackground() {
view.backgroundColor = UIColor(254, 248, 220)
}
As we can see, how succinct it has become to create a UIColor
. Share your thoughts and experience with Swift
’s powerful feature of type inference.