Lesson 56Structs

Extensions

What are Extensions?

Extensions add new functionality to existing types - even types you didn't create! You can add methods, computed properties, and initializers.

What You Can Add

Methods

Instance and type methods

Computed Properties

Not stored properties!

Initializers

Custom init methods

Nested Types

Types within types

Extension Syntax

extension TypeName {
    // new functionality
}

Best Uses

  • Extend built-in types (Int, String, etc.)
  • Organize code by functionality
  • Add protocol conformance
  • Keep related code together
main.swift
// EXTENSIONS
// Add new functionality to existing types
// WITHOUT modifying the original source code

// BASIC EXTENSION
struct Point {
    var x: Double
    var y: Double
}

// Add methods to Point later
extension Point {
    func distanceFromOrigin() -> Double {
        return (x * x + y * y).squareRoot()
    }

    func midpoint(to other: Point) -> Point {
        return Point(
            x: (self.x + other.x) / 2,
            y: (self.y + other.y) / 2
        )
    }
}

let p = Point(x: 3, y: 4)
print(p.distanceFromOrigin())  // 5.0

// EXTENDING BUILT-IN TYPES
extension Int {
    var squared: Int {
        return self * self
    }

    var isEven: Bool {
        return self % 2 == 0
    }

    func times(_ action: () -> Void) {
        for _ in 0..<self {
            action()
        }
    }
}

print(5.squared)   // 25
print(10.isEven)   // true

3.times {
    print("Hello!")  // Prints 3 times
}

// EXTENSION WITH COMPUTED PROPERTIES
extension String {
    var wordCount: Int {
        return self.split(separator: " ").count
    }

    var reversed: String {
        return String(self.reversed())
    }

    var isValidEmail: Bool {
        return self.contains("@") && self.contains(".")
    }
}

let text = "Hello Swift World"
print(text.wordCount)  // 3

let email = "[email protected]"
print(email.isValidEmail)  // true

// MUTATING METHODS IN EXTENSIONS
extension Point {
    mutating func moveBy(dx: Double, dy: Double) {
        x += dx
        y += dy
    }

    mutating func scale(by factor: Double) {
        x *= factor
        y *= factor
    }
}

var point = Point(x: 10, y: 20)
point.moveBy(dx: 5, dy: -5)
print(point)  // Point(x: 15, y: 15)

// EXTENSION WITH INITIALIZERS
extension Point {
    init(fromTuple tuple: (Double, Double)) {
        self.x = tuple.0
        self.y = tuple.1
    }

    init(polar radius: Double, angle: Double) {
        self.x = radius * cos(angle)
        self.y = radius * sin(angle)
    }
}

let p1 = Point(fromTuple: (3, 4))
let p2 = Point(polar: 5, angle: 0.927)

// EXTENDING DOUBLE
extension Double {
    var km: Double { return self * 1000 }
    var m: Double { return self }
    var cm: Double { return self / 100 }
    var mm: Double { return self / 1000 }
}

let marathon = 42.km + 195.m
print(marathon)  // 42195.0 meters

// ORGANIZE CODE WITH EXTENSIONS
struct User {
    var name: String
    var email: String
}

// Separate concerns into extensions
extension User {
    // Validation methods
    func isValid() -> Bool {
        return !name.isEmpty && email.contains("@")
    }
}

extension User {
    // Display methods
    func displayName() -> String {
        return name.capitalized
    }
}

Try It Yourself!

Extend Int with a computed property factorial that returns n!