For its name, extensions are used to extend an existing functionality. In Swift, you can extend classes, structures, protocols, and enumerations. Extensions are similar to categories in Objective-C except that extensions don't have names. It's very useful to add functionality to any type that you don't have access to its source code, such as native classes String, NSArray, and so on.
Using extensions to extend classes functionality
Getting ready
In Swift, syntax is pretty easy, and that's why it is awesome. To extend any type, just type the following:
extension TypeToBeExtended{ }
Inside the curly braces, you can add your extensions to the type to be extended. In extension, you can do the following:
- Adding instance- or class-computed properties
- Adding instance or class methods
- Adding new initializers
- Defining subscripts
- Adding nested types
- Conforming to protocols
Once you create an extension to any type, the new functionality will be available for all instances in the whole project.
How to do it...
- Create a new playground file in Xcode called Extensions.
- Create extension for double value by adding computing properties, as follows:
extension Double{ var absoluteValue: Double{ return abs(self) } var intValue: Int{ return Int(self) } } extension String{ var length: Int{ return self.characters.count } } let doubleValue: Double = -19.5 doubleValue.absoluteValue // 19.5 doubleValue.intValue // 19 extension Int{ func isEven() ->Bool{ return self % 2 == 0 } func isOdd() ->Bool{ return !isEven() } func digits() -> [Int]{ var digits = [Int]() var num = self repeat { let digit = num % 10 digits.append(digit) num /= 10 } while num != 0 return digits } } let num = 12345 num.digits() // [5, 4, 3, 2, 1]
How it works...
In Double type, we have added two computed properties. The computed properties are properties that will be calculated every time when it's called. We've added a property called absoluteValue, which returns the absolute value; same for intValue, which returns the integer value of double. Then, for any double value in the whole project, these two properties are accessible and can be used.
In the Int type, we have defined three new instance methods. The isEven() method should return true if this number is even, false otherwise, and the same logic applies for isOdd(). The third method that has some more logic is digits(), which returns array of digits in the number. The algorithm is simple; we get the last digit by getting the remainder of dividing the number by 10, and then skip the last digit by dividing by 10.
There's more...
Extensions are not meant to add new properties and methods only. You extend types by adding new initializers, mutating methods, and by defining subscripts.
Mutating instance methods
When you add instance methods, you can let them mutate (modify) the instance itself. In methods we've added before, we just do some logic and return a new value, and the instance value remains the same. With mutating, the value of instance itself will be changed. To do so, you have to mark your instance method with the mutating keyword. Let's take a look at an example:
extension Int{ mutating func square(){ self = self * self } mutating func double(){ self = self * 2 } } var value = 8 value.double() // 16 value.square() // 256
When you mark your method as mutating, it lets you to change self and assign new value to it.
Adding new initializer
Extensions allow you to add new initializer to the currently available initializer for any particular type. For example, let's take a look at the CGRect class. CGRect has three initializers: empty init; init with origin and size; and init with x, y, width, and height. We will add new initializer with a center point and a rectangular size. Let's take a look at how to do it:
extension CGRect{ init(center:CGPoint, size:CGSize){ let x = center.x - size.width / 2 let y = center.y - size.height / 2 self.init(x: x, y: y, width: size.width, height: size.height) } } let rect = CGRect(center: CGPoint(x: 50, y: 50), size: CGSizeMake(100, 80)) // {x 0 y 10 w 100 h 80}
Define subscripts
One of features that extensions provide to us is the ability to define subscripts to a particular type. Subscripting allows you to get value by calling [n] to get information at index n. Like array, when you access item at that index, you can do the same with any type you want. In the following example, we will add subscripting support to the String type:
extension String{ subscript(charIndex: Int) -> Character{ let index = startIndex.advancedBy(charIndex) return self[index] } } let str = "Hello" str[0] // "H"
To add subscript to type, just add the keyword subscript followed by index and the return type. In our preceding example, the subscript will return the character at a given index. We advanced the startIndex, which is a property in the String type and points to the first character by the input charIndex. Then, we return the character at that Index.