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
- 1Error Handling: Use Result type appropriately
- 2Generics: Write generic code when possible
- 3Protocols: Use protocols for abstraction
- 4Property Wrappers: Use for cross-cutting concerns
- 5Async/Await: Use modern concurrency
- 6Actors: Protect shared state
- 7Opaque Types: Hide implementation details
- 8Documentation: Document complex patterns
Advanced patterns make your Swift code professional and maintainable!