Lesson 75Protocols
Extensions
What are Extensions?
Extensions add new functionality to existing types - even types you don't own like Int, String, or Array. Incredibly powerful for organizing code!
What Extensions Can Add
Computed Properties
Add new computed properties
var squared: Int { ... }Methods
Add instance and type methods
func doSomething() { }Initializers
Add convenience initializers
init(custom: Type) { }Nested Types
Define new nested types
enum Kind { ... }Constrained Extensions
extension Array where Element: Equatable {
// Only available when Element is Equatable
}
// Only available when Element is Equatable
}
Limitations
- Cannot add stored properties
- Cannot override existing functionality
- Cannot add designated initializers to classes
- Cannot add property observers to existing properties
Best Practice: Code Organization
Use extensions to group related functionality:
- Protocol conformance in separate extensions
- UI setup vs data handling
- Private helpers in private extensions
main.swift
// EXTENSIONS
// Add new functionality to existing types
// 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(4.isEven) // true
3.times { print("Hello!") } // Prints 3 times
// EXTENDING STRING
extension String {
var reversed: String {
return String(self.reversed())
}
var wordCount: Int {
return self.split(separator: " ").count
}
func truncated(to length: Int) -> String {
if self.count <= length {
return self
}
return String(self.prefix(length)) + "..."
}
}
print("Hello".reversed) // olleH
print("Hello World Swift".wordCount) // 3
print("Hello World".truncated(to: 5)) // Hello...
// EXTENDING ARRAY
extension Array where Element: Numeric {
var sum: Element {
return reduce(0, +)
}
}
print([1, 2, 3, 4, 5].sum) // 15
// ADDING INITIALIZERS
extension Date {
init(year: Int, month: Int, day: Int) {
var components = DateComponents()
components.year = year
components.month = month
components.day = day
self = Calendar.current.date(from: components) ?? Date()
}
}
let birthday = Date(year: 2000, month: 6, day: 15)
// ADDING METHODS TO YOUR OWN TYPES
struct Point {
var x: Double
var y: Double
}
extension Point {
var magnitude: Double {
return (x * x + y * y).squareRoot()
}
func distance(to other: Point) -> Double {
let dx = other.x - x
let dy = other.y - y
return (dx * dx + dy * dy).squareRoot()
}
mutating func translate(dx: Double, dy: Double) {
x += dx
y += dy
}
}
// NESTED TYPES IN EXTENSIONS
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0: return .zero
case let x where x > 0: return .positive
default: return .negative
}
}
}
print(5.kind) // positive
print((-3).kind) // negative
// ORGANIZING CODE WITH EXTENSIONS
class ViewController {
var title: String = ""
}
// Group related functionality
extension ViewController {
func setupUI() {
print("Setting up UI")
}
func configureNavigation() {
print("Configuring navigation")
}
}
extension ViewController {
func loadData() {
print("Loading data")
}
func saveData() {
print("Saving data")
}
}
// CONSTRAINED EXTENSIONS
extension Array where Element: Equatable {
func removingDuplicates() -> [Element] {
var result: [Element] = []
for element in self {
if !result.contains(element) {
result.append(element)
}
}
return result
}
}
let nums = [1, 2, 2, 3, 3, 3]
print(nums.removingDuplicates()) // [1, 2, 3]
// EXTENSION LIMITATIONS
// Cannot add stored properties
// Cannot override existing functionality
// Cannot add designated initializers to classesTry It Yourself!
Extend Double with properties for celsius and fahrenheit conversion, and a rounded(toPlaces:) method!