Advanced Swift Patterns for 2026
Production-ready patterns for modern Swift development
🎯 Result Builders
Result builders enable DSL-like syntax for constructing complex values.
SwiftUI-Style Builders
@resultBuilder
struct HTMLBuilder {
static func buildBlock(_ components: String...) -> String {
components.joined()
}
static func buildOptional(_ component: String?) -> String {
component ?? ""
}
static func buildEither(first component: String) -> String {
component
}
static func buildEither(second component: String) -> String {
component
}
}
func html(@HTMLBuilder content: () -> String) -> String {
"<html>\(content())</html>"
}
// Usage
let page = html {
"<head><title>My Page</title></head>"
"<body>"
"<h1>Welcome</h1>"
"</body>"
}
Custom View Builder
@resultBuilder
struct ViewBuilder {
static func buildBlock<Content: View>(_ content: Content) -> Content {
content
}
static func buildBlock<C0: View, C1: View>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> {
TupleView((c0, c1))
}
}
struct CustomContainer<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
content
}
}
🔄 Property Wrappers
Thread-Safe Property Wrapper
@propertyWrapper
struct Atomic<Value> {
private var value: Value
private let lock = NSLock()
var wrappedValue: Value {
get {
lock.lock()
defer { lock.unlock() }
return value
}
set {
lock.lock()
defer { lock.unlock() }
value = newValue
}
}
init(wrappedValue: Value) {
self.value = wrappedValue
}
}
// Usage
class Counter {
@Atomic var count = 0
func increment() {
count += 1 // Thread-safe
}
}
UserDefaults Property Wrapper
@propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
let storage: UserDefaults
var wrappedValue: T {
get {
storage.object(forKey: key) as? T ?? defaultValue
}
set {
storage.set(newValue, forKey: key)
}
}
var projectedValue: Binding<T> {
Binding(
get: { wrappedValue },
set: { wrappedValue = $0 }
)
}
init(wrappedValue: T, _ key: String, storage: UserDefaults = .standard) {
self.key = key
self.defaultValue = wrappedValue
self.storage = storage
}
}
// Usage
struct Settings {
@UserDefault("username", storage: .standard)
var username: String = "Guest"
@UserDefault("isDarkMode", storage: .standard)
var isDarkMode: Bool = false
}
🎭 Type Erasure
AnyPublisher Pattern
protocol DataProvider {
associatedtype Output
func fetch() -> Output
}
// Type erasure wrapper
struct AnyDataProvider<Output>: DataProvider {
private let _fetch: () -> Output
init<P: DataProvider>(_ provider: P) where P.Output == Output {
_fetch = provider.fetch
}
func fetch() -> Output {
_fetch()
}
}
// Usage
struct UserProvider: DataProvider {
func fetch() -> User {
User(id: "1", name: "Alice")
}
}
let provider: AnyDataProvider<User> = AnyDataProvider(UserProvider())
🔐 Phantom Types
Phantom types add compile-time safety without runtime overhead.
enum Validated {}
enum Unvalidated {}
struct Email<State> {
let value: String
private init(_ value: String) {
self.value = value
}
}
extension Email where State == Unvalidated {
init(raw: String) {
self.init(raw)
}
func validated() -> Email<Validated>? {
guard value.contains("@"), value.contains(".") else {
return nil
}
return Email<Validated>(value)
}
}
extension Email where State == Validated {
func send(message: String) {
print("Sending to \(value): \(message)")
}
}
// Usage
let email = Email<Unvalidated>(raw: "test@example.com")
if let validated = email.validated() {
validated.send(message: "Hello!") // ✅ Type-safe
}
// let invalid = Email<Unvalidated>(raw: "invalid")
// invalid.send(message: "Hi") // ❌ Compile error - can't send unvalidated
🎯 KeyPath Magic
Dynamic Member Lookup
@dynamicMemberLookup
struct Settings {
private var storage: [String: Any] = [:]
subscript<T>(dynamicMember key: String) -> T? {
get { storage[key] as? T }
set { storage[key] = newValue }
}
}
var settings = Settings()
settings.apiKey = "abc123"
settings.timeout = 30
let key: String? = settings.apiKey
KeyPath Sorting
extension Sequence {
func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>) -> [Element] {
sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
}
}
struct User {
let name: String
let age: Int
}
let users = [
User(name: "Alice", age: 30),
User(name: "Bob", age: 25)
]
let sortedByAge = users.sorted(by: \.age)
let sortedByName = users.sorted(by: \.name)
🚀 Async Sequences
Custom AsyncSequence
struct CountdownSequence: AsyncSequence {
typealias Element = Int
let start: Int
let delay: Duration
struct AsyncIterator: AsyncIteratorProtocol {
var current: Int
let delay: Duration
mutating func next() async -> Int? {
guard current > 0 else { return nil }
try? await Task.sleep(for: delay)
defer { current -= 1 }
return current
}
}
func makeAsyncIterator() -> AsyncIterator {
AsyncIterator(current: start, delay: delay)
}
}
// Usage
for await count in CountdownSequence(start: 5, delay: .seconds(1)) {
print(count) // 5, 4, 3, 2, 1
}
🎨 Protocol Witnesses
Replace protocols with concrete types for better performance.
// Traditional protocol
protocol Validator {
func validate(_ value: String) -> Bool
}
// Protocol witness (faster)
struct Validator<T> {
let validate: (String) -> Bool
}
// Concrete validators
extension Validator {
static var email: Validator<String> {
Validator { $0.contains("@") && $0.contains(".") }
}
static var notEmpty: Validator<String> {
Validator { !$0.isEmpty }
}
}
// Usage
let emailValidator = Validator<String>.email
emailValidator.validate("test@example.com") // true
🔥 Opaque Types
// Return opaque type instead of protocol
func makeView() -> some View {
VStack {
Text("Hello")
Text("World")
}
}
// Generic opaque return
func makePublisher<T>() -> some Publisher<T, Never> {
Just(value)
.delay(for: .seconds(1), scheduler: DispatchQueue.main)
}
📦 Existential Types (Swift 5.7+)
// Old way
protocol Animal {
func makeSound() -> String
}
let animals: [Animal] = [Dog(), Cat()] // Implicit existential
// New explicit syntax
let animals: [any Animal] = [Dog(), Cat()]
// Constrained existential
func feed(_ animal: any Animal & Hashable) {
// animal must conform to both Animal and Hashable
}
🎯 Practice Challenges
Challenge 1: Build a Type-Safe Builder
Create a SQL query builder using result builders that prevents invalid queries at compile time.
Challenge 2: Thread-Safe Cache
Implement a generic cache with property wrappers that's thread-safe and supports expiration.
Challenge 3: Phantom Type State Machine
Create a state machine using phantom types where invalid state transitions are compile errors.
Next: Concurrency Patterns →