Skip to content
All essays
iOSMarch 27, 202513 min

Swift Advanced Patterns: Professional Development

Master advanced Swift patterns. Result builders, property wrappers, and generic programming.

Ü
Ümit Uz
Mobile & Full Stack Developer

Master advanced Swift patterns to write cleaner, more maintainable code. Learn result builders, property wrappers, and generics.

Result Type

Custom Result Type

swift
enum Result<T> {
    case success(T)
    case failure(Error)

    var value: T? {
        if case .success(let value) = self {
            return value
        }
        return nil
    }

    var error: Error? {
        if case .failure(let error) = self {
            return error
        }
        return nil
    }
}

// Usage
func divide(_ a: Int, by b: Int) -> Result<Int> {
    guard b != 0 else {
        return .failure(DivisionError.divisionByZero)
    }
    return .success(a / b)
}

enum DivisionError: Error {
    case divisionByZero
}

let result = divide(10, by: 2)
switch result {
case .success(let value):
    print("Result: \(value)")
case .failure(let error):
    print("Error: \(error)")
}

Property Wrappers

Custom Property Wrapper

swift
@propertyWrapper
struct Capitalized {
    var wrappedValue: String = "" {
        didSet {
            wrappedValue = wrappedValue.capitalized
        }
    }

    var projectedValue: String {
        wrappedValue.lowercased()
    }
}

struct User {
    @Capitalized var name: String
    var displayName: String {
        $name
    }
}

let user = User(name: "john")
print(user.name)           // "John"
print(user.displayName)   // "john"

Property Wrapper with Parameters

swift
@propertyWrapper
struct Clamped<T: Comparable> {
    var wrappedValue: T
    let range: ClosedRange<T>

    init(wrappedValue: T, range: ClosedRange<T>) {
        self.range = range
        self.wrappedValue = wrappedValue.clamped(to: range)
    }

    var projectedValue: T {
        wrappedValue
    }
}

struct Temperature {
    @Clamped(range: -50...50) var celsius: Double = 0

    var fahrenheit: String {
        let f = celsius * 9/5 + 32
        return String(format: "%.1f°F", f)
    }
}

Result Builders

Build Custom DSL

swift
func buildString(build: (inout String) -> Void) -> String {
    var string = ""
    build(&string)
    return string
}

struct HTML {
    let content: String

    func render() -> String {
        content
    }

    func paragraph(_ content: String) -> HTML {
        HTML(content: "<p>\(content)</p>")
    }
}

let html = buildString { html in
    html.paragraph("Hello")
    html.paragraph("World")
}

print(html.render())
// <p>Hello</p><p>World</p>

Generic Patterns

Generic Networking

swift
class NetworkClient {
    func fetch<T: Decodable>(_ type: T.Type, from url: URL) async throws -> T {
        let (data, _) = try await URLSession.shared.data(from: url)
        return try JSONDecoder().decode(T.self, from: data)
    }
}

// Usage
struct User: Decodable {
    let id: String
    let name: String
}

let client = NetworkClient()
let user = try await client.fetch(User.self, from: url)

Generic Repository

swift
protocol Repository {
    associatedtype Entity
    func fetch(id: String) async throws -> Entity
    func save(_ entity: Entity) async throws
}

class UserRepository: Repository {
    typealias Entity = User

    func fetch(id: String) async throws -> User {
        // Fetch from API
        return try await NetworkClient().fetch(User.self, from: url)
    }

    func save(_ user: User) async throws {
        // Save to API
    }
}

Protocol Extensions

Default Implementations

swift
protocol Identifiable {
    var id: String { get }
}

extension Identifiable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }

    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.id == rhs.id
    }
}

struct User: Identifiable {
    let id: String
    let name: String
}

Key Path

Type-Safe Properties

swift
struct Person {
    let name: String
    let age: Int
}

let person = Person(name: "John", age: 30)

// KeyPath support
let nameKeyPath = \Person.name
let ageKeyPath = \Person.age

func getValue<T>(_ keyPath: KeyPath<Person, T>, from person: Person) -> T {
    person[keyPath: keyPath]
}

let name: String = getValue(nameKeyPath, from: person)

Associated Types

Flexible Protocols

swift
protocol Container {
    associatedtype Item
    mutating func add(_ item: Item)
    var count: Int { get }
}

struct Stack: Container {
    private var items: [Item] = []

    mutating func add(_ item: Item) {
        items.append(item)
    }

    var count: Int {
        items.count
    }
}

// Usage
let intStack = Stack<Int>()
intStack.add(1)

let stringStack = Stack<String>()
stringStack.add("Hello")

Opaque Types

Hide Implementation

swift
protocol Shape {
    func area() -> Double
}

struct Circle: Shape {
    let radius: Double

    func area() -> Double {
        .pi * radius * radius
    }
}

struct Rectangle: Shape {
    let width: Double
    let height: Double

    func area() -> Double {
        width * height
    }
}

func createShape() -> some Shape {
    Circle(radius: 10)
}

AsyncStream

Create Async Streams

swift
func generateNumbers() -> AsyncStream<Int> {
    return AsyncStream { continuation in
        for i in 1...10 {
            continuation.yield(i)
        }
        continuation.finish()
    }
}

Task {
    for await number in generateNumbers() {
        print("Number: \(number)")
    }
}

Actor Patterns

Concurrent Data

swift
actor DataManager {
    private var cache: [String: Data] = [:]

    func get(_ key: String) -> Data? {
        cache[key]
    }

    func set(_ data: Data, for key: String) {
        cache[key] = data
    }

    func clear() {
        cache.removeAll()
    }
}

let dataManager = DataManager()

Task {
    await dataManager.set(Data(), for: "key1")
    let data = await dataManager.get("key1")
}

Best Practices

  1. 1Error Handling: Use Result type appropriately
  2. 2Generics: Write generic code when possible
  3. 3Protocols: Use protocols for abstraction
  4. 4Property Wrappers: Use for cross-cutting concerns
  5. 5Async/Await: Use modern concurrency
  6. 6Actors: Protect shared state
  7. 7Opaque Types: Hide implementation details
  8. 8Documentation: Document complex patterns

Advanced patterns make your Swift code professional and maintainable!

Related essays

Next essay
Swift File Management: Documents and Storage