Swift Extensions
An extension adds new functionality to an existing type — without modifying its original source code. You can extend types you wrote yourself, Apple's built-in types, or even types from third-party libraries. Think of an extension like adding a new app to a phone: you are not rebuilding the phone, just giving it extra capability.
Basic Extension Syntax
extension Int {
func squared() -> Int {
return self * self
}
}
print(5.squared()) // Output: 25
print(12.squared()) // Output: 144The keyword self inside an extension refers to the value the method is called on — here, the integer itself.
Diagram: Extension Adds Without Replacing
Original Int type After extension
+---------------------------+ +---------------------------+
| + (addition) | | + (addition) |
| - (subtraction) | → | - (subtraction) |
| * (multiplication) | | * (multiplication) |
| ... (built-in methods) | | squared() ← NEW |
+---------------------------+ | isEven ← NEW |
+---------------------------+
Computed Properties in Extensions
Extensions can add computed properties, but not stored properties.
extension Int {
var isEven: Bool { self % 2 == 0 }
var isOdd: Bool { self % 2 != 0 }
var doubled: Int { self * 2 }
}
print(6.isEven) // Output: true
print(7.isOdd) // Output: true
print(4.doubled) // Output: 8Extending Double
extension Double {
var asCurrency: String {
return String(format: "$%.2f", self)
}
var asPercentage: String {
return String(format: "%.1f%%", self * 100)
}
}
print(9.99.asCurrency) // Output: $9.99
print(0.175.asPercentage) // Output: 17.5%Extending String
extension String {
var wordCount: Int {
return self.split(separator: " ").count
}
func repeat(_ times: Int) -> String {
return String(repeating: self, count: times)
}
var isPalindrome: Bool {
let clean = self.lowercased().filter { $0.isLetter }
return clean == String(clean.reversed())
}
}
print("Hello world Swift".wordCount) // Output: 3
print("ha".repeat(3)) // Output: hahaha
print("racecar".isPalindrome) // Output: true
print("swift".isPalindrome) // Output: falseExtending Your Own Types
Extensions keep large types organized by splitting functionality into logical sections.
struct Rectangle {
var width: Double
var height: Double
}
// Core math in an extension
extension Rectangle {
var area: Double { width * height }
var perimeter: Double { 2 * (width + height) }
var isSquare: Bool { width == height }
}
// Display in a separate extension
extension Rectangle {
func describe() {
print("Rectangle \(width)×\(height) | Area: \(area)")
}
}
let r = Rectangle(width: 5, height: 3)
r.describe()
print(r.isSquare) // Output: falseAdding Initializers via Extension
You can add new initializers to a struct through an extension. This preserves the automatic memberwise initializer Swift generates.
struct Point {
var x: Double
var y: Double
}
extension Point {
init(at distance: Double, angle: Double) {
self.x = distance * cos(angle)
self.y = distance * sin(angle)
}
static var origin: Point { Point(x: 0, y: 0) }
}
let p = Point(at: 5.0, angle: 0.0)
print(p.x) // Output: 5.0
let o = Point.origin
print(o.x) // Output: 0.0Protocol Conformance via Extension
You can make an existing type conform to a protocol entirely inside an extension. This separates concerns cleanly.
protocol Printable {
func prettyPrint()
}
struct Invoice {
var id: Int
var total: Double
}
extension Invoice: Printable {
func prettyPrint() {
print("Invoice #\(id) — Total: \(total.asCurrency)")
}
}
let inv = Invoice(id: 101, total: 249.0)
inv.prettyPrint() // Output: Invoice #101 — Total: $249.00Extending Protocols (Protocol Extensions)
Protocol extensions add default method implementations that every conforming type receives automatically.
protocol Greetable {
var name: String { get }
}
extension Greetable {
func greet() {
print("Hello, I'm \(name)!")
}
}
struct User: Greetable {
var name: String
}
struct Bot: Greetable {
var name: String
}
User(name: "Alice").greet() // Output: Hello, I'm Alice!
Bot(name: "R2D2").greet() // Output: Hello, I'm R2D2!Neither User nor Bot implements greet() — they both get it free from the protocol extension.
Extension Restrictions
| You CAN add via extension | You CANNOT add via extension |
|---|---|
| Computed properties | Stored properties |
| Methods (including mutating) | Property observers (didSet/willSet) |
| New initializers | Override existing methods |
| Subscripts | Designated initializers on classes |
| Nested types | |
| Protocol conformance |
Summary
Extensions add computed properties, methods, initializers, and protocol conformances to any existing type — yours or Apple's — without touching the original code. Use them to keep large types organized, to add convenience helpers to built-in types, and to attach protocol conformance to types cleanly. Extensions are one of the most practical everyday tools in Swift.
