← Swift EnglishChapter 11 of 13

Extensions and Generics

## Learning Objectives - Extend existing types with extensions - Use protocol delegation - Master generics basics - Write generic functions and types ## Extensions ### Adding Functionality ```swift extension Int { func squared() -> Int { return self * self } } let number = 5 print(number.squared()) // 25 ``` ### Adding Computed Properties ```swift extension Double { var kmToMiles: Double { return self * 0.621371 } var milesToKm: Double { return self * 1.60934 } } let distance = 10.0 print("\(distance) km = \(distance.kmToMiles) miles") ``` ### Adding Initializers ```swift struct Point { var x: Int var y: Int } extension Point { init(xy: Int) { self.init(x: xy, y: xy) } } let origin = Point(xy: 0) // Point(x: 0, y: 0) ``` ### Adding Methods ```swift extension Array { func average() -> Double? { guard !isEmpty else { return nil } return Double(reduce(0, +)) / Double(count) } } let scores = [90, 85, 92, 88] print(scores.average()) // Optional(88.75) ``` ## Protocol Conformance ### Extending to Conform ```swift protocol Printable { func description() -> String } extension Int: Printable { func description() -> String { return "Number: \(self)" } } print(42.description()) // "Number: 42" ``` ### Adding Protocol Requirements ```swift extension Array where Element: Equatable { func contains(_ element: Element) -> Bool { for item in self { if item == element { return true } } return false } } let nums = [1, 2, 3, 4, 5] print(nums.contains(3)) // true print(nums.contains(10)) // false ``` ## Protocol Delegation ### Defining Protocols ```swift protocol DataHandlerDelegate: AnyObject { func didReceiveData(_ data: Data) func didFailWithError(_ error: Error) } class DataHandler { weak var delegate: DataHandlerDelegate? func fetchData() { // ... fetch data let data = Data() delegate?.didReceiveData(data) } } ``` ### Implementing Delegate ```swift class ViewController: DataHandlerDelegate { let handler = DataHandler() init() { handler.delegate = self } func didReceiveData(_ data: Data) { print("Received \(data.count) bytes") } func didFailWithError(_ error: Error) { print("Error: \(error)") } } ``` ### Delegate Pattern Benefits - Loose coupling - Flexibility - Multiple delegates possible - Clear responsibility separation ## Generics ### Why Generics? ```swift // Without generics - repeated code func swapInts(_ a: inout Int, _ b: inout Int) { let temp = a a = b b = temp } func swapStrings(_ a: inout String, _ b: inout String) { let temp = a a = b b = temp } // With generics - one function func swap(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp } var x = 1, y = 2 swap(&x, &y) var s1 = "Hello", s2 = "World" swap(&s1, &s2) ``` ## Generic Functions ### Syntax ```swift func identity(_ value: T) -> T { return value } let num = identity(42) // Inferred as Int let str = identity("hello") // Inferred as String ``` ### Multiple Type Parameters ```swift func combine(_ a: A, _ b: B) -> (A, B) { return (a, b) } combine(1, "one") // (1, "one") ``` ### Type Constraints ```swift // Comparable constraint func maximum(_ a: T, _ b: T) -> T { return a > b ? a : b } maximum(5, 10) // 10 maximum("apple", "banana") // "banana" ``` ## Generic Types ### Generic Struct ```swift struct Stack { var items: [Element] = [] mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element? { return items.popLast() } func peek() -> Element? { return items.last } } var intStack = Stack() intStack.push(1) intStack.push(2) print(intStack.pop()) // Optional(2) var stringStack = Stack() stringStack.push("Hello") stringStack.push("World") ``` ### Generic Class ```swift class Queue { private var items: [Element] = [] func enqueue(_ item: Element) { items.append(item) } func dequeue() -> Element? { return items.removeFirst() } func peek() -> Element? { return items.first } } ``` ### Generic Enum ```swift enum Result { case success(Value) case failure(Error) } let success: Result = .success(42) let failure: Result = .failure("Error occurred") ``` ## Extension Type Constraints ### Type Constraints Syntax ```swift func findIndex(of value: T, in array: [T]) -> Int? { for (index, item) in array.enumerated() { if item == value { return index } } return nil } ``` ### Multiple Constraints ```swift func findString(in collection: T) -> T.Element? where T.Element == String { return collection.first(where: { !$0.isEmpty }) } ``` ### Protocol Constraints ```swift func process(values: [T]) -> T? { return values.filter { $0 > 0 }.max() } process(values: [1, -2, 3, 0]) // Optional(3) ``` ## Extensions with Generics ### Extending Generic Types ```swift extension Stack where Element: Comparable { func sorted() -> [Element] { return items.sorted() } } var stack = Stack() stack.push(3) stack.push(1) stack.push(2) print(stack.sorted()) // [1, 2, 3] ``` ### Extension with Self ```swift extension Numeric { func squared() -> Self { return self * self } } let num: Int = 5 print(num.squared()) // 25 let dbl: Double = 3.0 print(dbl.squared()) // 9.0 ``` ## Associated Types ### Protocol with Associated Type ```swift protocol Container { associatedtype Item mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } } ``` ### Generic Struct Conforming ```swift struct IntContainer: Container { private var items: [Int] = [] mutating func append(_ item: Int) { items.append(item) } var count: Int { items.count } subscript(i: Int) -> Int { return items[i] } } ``` ## Opaque Types ### some Keyword ```swift protocol Shape { func draw() } struct Circle: Shape { func draw() { print("Circle") } } struct Square: Shape { func draw() { print("Square") } } func makeShape() -> some Shape { return Circle() } let shape = makeShape() shape.draw() // Circle ``` ### Use Cases ```swift // SwiftUI uses opaque return types func makeContentView() -> some View { Text("Hello") } ``` ## Summary - Extensions add functionality to existing types - Computed properties, methods, initializers can be added - Use `where` clause for conditional conformance - Delegation separates concerns via protocols - Generics enable type-safe reusable code - Type constraints: `` - Generic functions: `func identity(_ x: T) -> T` - Generic types: `struct Stack` - Associated types for generic protocols - `some` for opaque return types

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →