Continuing with our series of Swift tutorials, we’ll be discussing and playing around with Swift Extension in this tutorial.

Swift Extension

Swift Extension is a useful feature that helps in adding more functionality to an existing Class, Structure, Enumeration or a Protocol type. This includes adding functionalities for types where you don’t have the original source code too (extensions for Int, Bool etc. types).

Following are the essential functionalities that Swift Extension offer us:

  1. Add computed instance properties and computed type properties
  2. Define instance methods and type methods
  3. Provide new initializers
  4. Define subscripts
  5. Define and use new nested types
  6. Make an existing type conform to a protocol

Note: Stored Properties can’t be added to Extensions. Swift Extensions don’t support overriding properties and method implementations.

Swift Extension Syntax

Following is the syntax used for creating swift extension.


extension ClassStructEnumOrProtocolNameGoesHere {
    //add functionality to the above type
}

Swift Class Extension Example

Let’s open our Xcode playground and start working with Extensions.


extension Int {
    var square : Int{
        return self*self
    }
    func cube()->Int{
        return self*self*self
    }
    mutating func incrementBy5() {
        self = self + 5
    }
}
var x : Int = 5
print(x.square) //prints "25n"
print(x.cube()) //prints "125n"
x.incrementBy5() // 10

In the above code, we’ve created a read-only computed property to calculate the square of the number. Hence get is omitted.

To modify the value of the type itself, a mutating Function is used.


extension String {
    var length: Int {
        get {
            return self.characters.count
        }
    }
    mutating func addString(str: String) {
        self = self + str
    }
}
var stringA = "Hello"
stringA.length  // 5
stringA.addString(str: "World") //HelloWorld
stringA.length // 10

Implementing Initialisers in Swift Extensions

  • Swift Extensions can add new initialisers to existing types.
  • Extensions for classes can add new convenience initialisers. Designated Initialisers for classes must be present in the class implementation only.
  • Deinitialisers aren’t possible in extensions.

Note: A designated initializer is the primary initializer for a class. It must fully initialize all properties introduced by its class. A class can have more than one designated initializer.

An example implementation with class is given below.


class A {
    var name : String
    var age : Int
    init(name: String, age: Int) {
        self.age = age
        self.name = name
    }
}
extension A {
    convenience init() {
        self.init(name: "No name yet", age: 0)
    }
}
var a = A()
print(a.name) //prints "No name yet"
print(a.age) //prints 0

We know that structs create the default initialisers with all the properties for us as shown below:


struct S {
    var name : String
    var age : Int
}
var s = S(name: "Anupam", age: 23)

Once we define our own initializer, Swift forbids us from using the above default initialiser:


struct S {
    var name : String
    var age : Int
    init(age : Int) {
        self.age = age
        self.name = "A boy has no name"
    }
}
var s = S(age: 16)
s.name //A boy has no name
s.age //16

Using the power of Extensions we can preserve the default initalisers too that structs provide as shown below.


struct S {
    var name : String
    var age : Int
}
extension S {
    init(age : Int) {
        self.age = age
        self.name = "A boy has no name"
    }
}
var s = S(age: 16)
var s1 = S(name: "Anupam", age: 23)

Swift Extension Subscripts

Swift Extensions can add new subscripts to an existing type as shown below.


extension String {
    var length: Int {
        return self.characters.count
    }
    subscript (i: Int) -> String {
        return self[i ..< i + 1]
    }
    subscript (r: Range) -> String {
        let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                            upper: min(length, max(0, r.upperBound))))
        let start = index(startIndex, offsetBy: range.lowerBound)
        let end = index(start, offsetBy: range.upperBound - range.lowerBound)
        return String(self[start ..< end])
    }
}
var sa : String = "hello"
sa[2] // l
sa[0..<4] // hell

Awesome! We’ve created an extension for a string through which we can access a character or a range of characters just like an Array.

Swift Protocol Extension

We’ve adopted TableView protocols. There’s an alternative though. We can write an extension and conform the protocols to it thereby making the code organized and structured better than before as shown below.


//Earlier approach.
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
    //All the functions of both the protocols must be implemented here.
}
//Newer and Better Approach
class ViewController : UIViewController {
    //Keep class specific code here
}
extension ViewController : UITableViewDataSource {
    //Implement the methods of DataSource protocol only.
}
extension ViewController : UITableViewDelegate{
    //Implement the methods of Delegate protocol only.
}

Navigating through the code structure becomes much easier when protocols are adopted in extensions.


class C : Name
{
    var name: String
    init(name: String) {
        self.name = name
    }
}
extension C : Greet {
    func greet() -> String{
        return "Hello, (name)"
    }
}
var c = C(name: "Anupam")
c.greet() //prints "Hello, Anupam"

Nested Types using Swift Extension

Extensions can be useful for creating nested types of classes, structures or enumerations.
Let’s explain this by an example.


extension String{
    var length: Int {
        get {
            return self.characters.count
        }
    }
    enum Length{
        case Zero, NotZero
    }
    var isZero : Length{
        switch self.length{
        case 0 : return .Zero
        default : return .NotZero
        }
    }
}
func checkLength(s: String){
    switch  s.isZero {
    case .Zero:
        print("The length of your string is zero")
    case .NotZero:
        print("The length of your string is NOT zero")
    }
}
var myString = ""
checkLength(s: myString) //prints "The length of your string is zeron"
myString = "Hi"
checkLength(s: myString) //prints "The length of your string is NOT zeron"

We’ve able to group strings based on their length using enums inside an Extension.

This brings an end to swift extension tutorial. Extensions, when used correctly can be very handy in your Swift Programming.

References : Apple Docs

By admin

Leave a Reply

%d bloggers like this: