Dispatch (Swift) 1. What is it? Dispatch is the mechanism that decides which implementation a call will execute (and when that decision is made: compile-time vs runtime). In Swift, dispatch choices directly affect polymorphism, correctness (especially with protocol extensions), and performance. 2. What problem does it solve? Enables polymorphism (same call, different behavior) via inheritance or protocols. Balances flexibility vs performance (dynamic lookup vs direct calls). Defines how overrides, protocol conformances, and runtime features (KVO/swizzling) work. 3. Types / Categories Kind Trigger / Where it appears Mechanism Typical cost Notes Static dispatch (direct call) struct/enum, final methods/classes, static functions, many generics Compiler emits a direct call Lowest Most optimizable (inline, specialize) Virtual dispatch (vtable) class inheritance + overridable methods vtable lookup Low–medium Enables override polymorphism Protocol dispatch (witness table) Calling protocol requirements through a protocol type witness table lookup Low–medium Key for any Protocol calls Obj-C message dispatch @objc dynamic, KVC/KVO, swizzling, selectors objc_msgSend Medium–high Most dynamic, least optimizable 4. How does it work in Swift? Quick decision tree Value types (struct/enum) → usually static dispatch final class or final func → static dispatch (cannot be overridden) Non-final class methods (especially overridden) → vtable dispatch Protocol requirement calls via any Protocol → witness table dispatch Protocol extension methods → static dispatch (common footgun) Generic T: Protocol → often specialized by the compiler → can become close to static dispatch @objc dynamic → Objective-C runtime dispatch (objc_msgSend) Why protocol extensions can surprise you A method implemented in a protocol extension is not always dispatched through the witness table. If you call it via an existential (let x: any P = ...), Swift may bind to the extension implementation (static) instead of the conforming type’s method (dynamic through witness table). Rule of thumb: ...
Cheat Sheets All cheat sheets follow a strict, shared structure. Each document is designed for quick recall rather than full tutorials. If you are adding a new cheat sheet: Use the template in cheat-sheets/_template.md Keep it under 1–2 screens Focus on “why” and “when”, not syntax
some vs any (Opaque vs Existential) 1. What is it? some defines an opaque type: the concrete type is fixed but hidden from the caller. any defines an existential type: the concrete type is erased and can vary at runtime. 2. What problem does it solve? They let APIs abstract over types: some: abstraction without losing static type information any: abstraction when heterogeneity or runtime flexibility is required 3. Types / Categories Opaque types (some P) Compile-time concrete type Single underlying type per declaration Existential types (any P) Runtime type-erased container Can hold multiple concrete types over time 4. How does it work in Swift? some P Compiler generates a hidden concrete generic Uses static dispatch, specialization, and inlining Backed by vtables/witness tables known at compile time any P Stored as an existential container Uses dynamic dispatch via witness tables May allocate (inline buffer vs heap) depending on size 5. Dangerous corners / Footguns some cannot return different concrete types across branches any loses associated type and Self information Existentials inhibit specialization and inlining Existential boxing can cause unexpected heap allocations Mixing any P with generics often causes silent performance cliffs 6. When should I use which? Use some when: You control the implementation You want abstraction and performance The concrete type is stable per API Use any when: You need heterogenous collections The concrete type varies at runtime API boundaries require type erasure Prefer generics over any when the caller can benefit from specialization 7. 30-second summary some = hidden concrete type, fast, statically dispatched any = type-erased container, flexible, dynamically dispatched some preserves optimization; any trades performance for flexibility Default to some (or generics); reach for any only when necessary
SwiftUI View Identity & Lifetime What is it? SwiftUI’s model where View values are cheap, ephemeral structs, while identity determines which underlying persistent backing store (state, subscriptions, render resources) is reused across updates. “Lifetime” is mostly about the lifetime of that backing store, not the View value. What problem does it solve? Enables a pure(ish) declarative UI where the framework can diff successive body results and update only what changed, while preserving state for “the same” conceptual view across recomputations. ...
Associated Types in Swift Associated types let protocols declare a placeholder type that conforming types must specify. They enable protocol-based code to stay generic without forcing every consumer to name a concrete type up front. Why Use Associated Types? Express relationships between inputs/outputs without locking into a concrete type. Keep protocol APIs lightweight while letting conformers choose their own models. Compose with generics and opaque types to avoid long type signatures. Basic Syntax 1 2 3 4 5 6 7 8 protocol DataProvider { associatedtype Item func items() -> [Item] } struct LocalProvider: DataProvider { func items() -> [String] { ["alpha", "beta"] } } LocalProvider satisfies Item with String, and callers can rely on items() returning [String] inside generic contexts. ...
Collections and Algorithms (with version cues) Sequence vs Collection, common transforms, and performance considerations. Version Quick Reference Swift 5.x+: standard library offers CoW collections, lazy views, and SIMD-backed ContiguousArray. Swift 5.7+: improved type inference with primary associated types; any spelling required for existentials. Swift 5.9+: parameter packs/variadic generics (advanced; not covered here). Sequence vs Collection Sequence: single-pass iteration guaranteed; may be destructive. Use when you don’t need indices or multiple passes. Collection: multi-pass with stable indices (startIndex/endIndex). Prefer for in-memory data you traverse multiple times. Common Transforms map/compactMap/flatMap: convert, filter nils, flatten. filter: keep matching elements; be mindful of allocation on large data. reduce: combine into a single value; prefer reduce(into:) to avoid intermediate allocations. 1 2 3 4 let upper = names.map { $0.uppercased() } let numbers = strings.compactMap(Int.init) let flattened = [[1,2],[3]].flatMap { $0 } let counts = words.reduce(into: [:]) { $0[$1, default: 0] += 1 } Lazy Views Use .lazy to defer work and reduce intermediate allocations, especially after filters and maps chained together. 1 let firstBig = numbers.lazy.filter { $0 > 1000 }.first Slicing and Subsequence Slices (ArraySlice, Substring) share storage with the base collection; copy to Array/String if you need long-term storage. 1 2 let slice = array[2...] // ArraySlice let copy = Array(slice) // makes an owned copy Sorting and Searching sorted() returns a new array; sort() mutates in-place (more memory efficient). For membership checks on large datasets, consider Set or Dictionary over linear contains. Mutations and Performance Prefer reserveCapacity on arrays and dictionaries when size is known to reduce reallocations. For hot paths, avoid repeated removeFirst() on arrays (O(n)); use indices or popLast() where order permits. Algorithms to Remember zip to iterate pairs; stride(from:to:by:) for steps; prefix/while, drop/while for stream-like processing. grouping via Dictionary(grouping:by:); chunks manually via stride or rolling indices. Testing Add property-based checks (if available) for algorithms to ensure invariants (e.g., sorted output length matches input). Benchmark critical paths with measure in XCTest or simple timing helpers; ensure lazy vs eager choices are intentional.
Combine and AsyncSequence (with version cues) How to bridge publishers to async/await, manage backpressure, and handle cancellation. Version Quick Reference iOS 13 / Swift 5.1: Combine introduced with Publisher, operators, and schedulers. iOS 15 / Swift 5.5: AsyncSequence and Publisher.values bridge Combine to async/await. Swift 6+: stricter concurrency checking surfaces Sendable and actor-isolation issues in custom publishers/operators. Bridging Combine to Async/Await Use publisher.values (iOS 15+) to consume a publisher as an AsyncSequence. 1 2 3 for await value in publisher.values { handle(value) } For single values, prefer try await publisher.first(where:) or async variants instead of promise-style bridges. Cancellation and Backpressure Cancellation in Combine maps to Task cancellation in async bridges. Respect Task.isCancelled when producing values manually. Backpressure is automatic for many operators, but custom Publisher implementations should consider demand. When bridging to async, the consumer naturally pulls values; avoid buffering unboundedly. Error Handling Combine uses Failure associated type; Never means no errors. When bridging, failures throw in async contexts. 1 2 3 4 5 6 7 do { for try await value in fallible.values { handle(value) } } catch { // handle Combine Failure here } Common Patterns UI: map publishers to async functions in SwiftUI task {} blocks; cancel tasks on disappear. Testing: use AsyncStream to feed deterministic values into async code, or use TestScheduler for pure Combine pipelines. Replacing Combine with AsyncSequence For new code on iOS 15+, prefer AsyncSequence for simpler async streams. Use AsyncStream/AsyncThrowingStream to wrap callback-based APIs. 1 2 3 4 5 6 7 8 9 10 func notifications() -> AsyncStream<Notification> { AsyncStream { continuation in let token = NotificationCenter.default.addObserver(forName: .foo, object: nil, queue: nil) { note in continuation.yield(note) } continuation.onTermination = { _ in NotificationCenter.default.removeObserver(token) } } } Concurrency Safety Ensure custom publishers and subjects are Sendable if they cross actors/threads. Consider using actors to guard mutable state in publishers you own. Testing For Combine: use XCTest with expectations or TestScheduler; assert output sequences and completion. For async bridges: write async tests with for await and verify cancellation by cancelling the parent Task.
How to create a constants file? Create a new Constants.swift file. Create a Struct inside the Constants.swift file. You name the file Constants, K, or what you want. :) Add static let properties to the Struct. Like below. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 struct K { static let cellIdentifier = "ReusableCell" static let cellNibName = "MessageCell" static let registerSegue = "RegisterToChat" static let loginSegue = "LoginToChat" // If you wish, you can add a group for similar content. struct BrandColors { static let purple = "BrandPurple" static let lightPurple = "BrandLightPurple" static let blue = "BrandBlue" static let lighBlue = "BrandLightBlue" } struct FStore { static let collectionName = "messages" static let senderField = "sender" static let bodyField = "body" static let dateField = "date" } } Usage print(K.cellIdentifier) print(K.BrandColors.purple)
Core Data Adding CoreData to existing project Create a new data model file: Xcode > File > New > File > DataModel Modify AppDelegate.swift file 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import UIKit import CoreData @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true } /* other AppDelegate methods, if you need.. */ func applicationWillTerminate(_ application: UIApplication) { self.saveContext() } // MARK: - Core Data stack // lazy: A lazy var is a property whose initial value is not calculated until the first time it's called. lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "DataModel") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() // MARK: - Core Data Saving support func saveContext () { let context = persistentContainer.viewContext if context.hasChanges { do { try context.save() } catch { let nserror = error as NSError fatalError("Unresolved error \(nserror), \(nserror.userInfo)") } } } } Create your entities using DataModel file Done! 🎉 CREATE/SAVE data 1 2 3 4 5 6 7 8 9 10 11 12 import CoreData // get context from appdelegate let context = (UIApplication.shared.delegate as! AppDelegate ).persistentContainer.viewContext // create item let newItem = Item(context: context) newItem.title = "New item" // save changes to db do { try context.save() } catch { print("Error saving context, \(error)") } READ data 1 2 3 4 5 6 7 // Item is our entity let request: NSFetchRequest<Item> = Item.fetchRequest() do { itemArray = try context.fetch(request) } catch { print("Error fetching data from context, \(error)") } UPDATE data 1 2 3 4 5 itemArray[indexPath.row].setValue("Updated item", forKey: "title") // or itemArray[indexPath.row].isDone = !itemArray[indexPath.row].isDone // and after context.save() // inside do-catch block DELETE/DESTROY data 1 2 3 4 context.delete(itemArray[indexPath.row]) // must be first itemArray.remove(at: indexPath.row) // and after context.save() // inside do-catch block QUERYING data Useful Documents NSPredicate Cheatsheet NSPredicate by NSHipster Querying using Search Bar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 extension ViewController: UISearchBarDelegate { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { if let searchText = searchBar.text { let request: NSFetchRequest<Item> = Item.fetchRequest() request.predicate = NSPredicate(format: "title CONTAINS[cd] %@", searchText) // c: case insensetive d: diacritic insensetive request.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)] do { itemArray = try context.fetch(request) } catch { print("Error fetching data from context, \(error)") } tableView.reloadData() } } }
A absence: yokluk absent: mevcut olmayan altogether: tamamen appropriate: Uygun, yerinde, özgü. assertion: iddia assignment: atama B behavior: davranış C competent: yetkili compound: birleştirmek, bileşik, karışık concise: özlü confident: kendinden emin D deduce: Sonuç çıkarmak, anlamak. despite: aksine distinct: belirgin, farklı, ayrı E encounter: rastlamak exclamation: ünlem explicitly: açıkça in a clear and detailed manner, leaving no room for confusion or doubt. “the essay should state explicitly how the facts support the thesis” ...
Error Handling in Swift (with version cues) Practical patterns for throwing, typed throws, and interop. Version Quick Reference Swift 5.x: untyped throws, rethrows, Result, try?, try!. Swift 6+: typed throws (throws(SomeError)) available by default; strict concurrency checking may surface error-sendability issues. Basics Use throws for recoverable issues; keep errors small and domain-specific. Prefer enums conforming to Error; include minimal context (payloads or userInfo when bridging). 1 2 3 4 5 6 enum NetworkError: Error { case offline, timeout(seconds: Int) } func fetch() throws -> Data { guard isOnline else { throw NetworkError.offline } return Data() } Typed Throws (Swift 6+) Specify the exact error type to enable exhaustive handling at call sites. 1 2 3 4 5 6 7 8 9 10 11 enum LoginError: Error { case offline, invalidCredentials } func login(email: String, password: String) throws(LoginError) -> Session { ... } do { _ = try login(email: "a@b.com", password: "pw") } catch LoginError.offline { // precise recovery } catch { // optional fallback if bridging from ObjC or unexpected errors arise } Rethrows Use rethrows when a function only throws if its function parameter throws—helpful for higher-order functions. 1 2 3 func mapOrThrow<T>(_ values: [String], transform: (String) throws -> T) rethrows -> [T] { try values.map(transform) } Result vs throws throws is ergonomic inside async/await and linear code. Result is useful for storing or combining errors, or when API shape must be synchronous but errorful. 1 let outcome: Result<Data, NetworkError> = Result { try fetch() } Async Error Propagation async throws pairs naturally; prefer this over callback-based completion handlers. For cancellation, treat CancellationError distinctly to avoid masking user intent. 1 2 3 4 5 6 7 func loadProfile() async throws -> Profile { ... } do { _ = try await loadProfile() } catch is CancellationError { // respect user cancellation } Bridging and Interop Objective-C NSError maps to Swift Error; annotate ObjC with NS_SWIFT_NAME and NSError ** patterns. When exposing Swift APIs to ObjC, typed throws are not visible; design ObjC-friendly overloads if needed. Testing Errors Use XCTAssertThrowsError with pattern matching to assert specific cases. For typed throws, tests become clearer and more exhaustive. 1 2 3 XCTAssertThrowsError(try login(email: "", password: "")) { error in XCTAssertEqual(error as? LoginError, .invalidCredentials) }
Generics and Constraints (with version cues) Practical patterns for generics, protocol constraints, and existential usage. Version Quick Reference Swift 5.6+: any keyword required to spell existential types explicitly. Swift 5.7 (Xcode 14): primary associated types, improved existential type inference, better Sendable checks behind flags. Swift 5.9 (Xcode 15): parameter packs and variadic generics (advanced; skip unless you need them). Swift 6+: strict concurrency checking is the default; existential/Sendable diagnostics are stricter. where Clauses and Conditional Conformance Use where to keep function signatures clear and constraints localized. Conditional conformance lets you add protocol adoption only when generic parameters meet requirements. 1 2 3 4 5 6 extension Array: Encodable where Element: Encodable {} func merge<P: Sequence, Q: Sequence>(_ lhs: P, _ rhs: Q) -> [P.Element] where P.Element == Q.Element { lhs + rhs } Primary Associated Types (Swift 5.7) Protocols can surface key associated types in angle brackets, reducing boilerplate when constraining existentials. 1 2 3 4 5 6 7 8 protocol IteratorProtocol<Element> { associatedtype Element mutating func next() -> Element? } // Prior to 5.7: `any IteratorProtocol` lost the element type easily. // With a primary associated type you can write: let ints: any IteratorProtocol<Int> Existentials vs Opaque Types any creates a type-erased box; some preserves a single concrete type. Prefer some for return types when the function always yields one concrete conformer; use any when multiple conformers must flow through the same API or be stored together. 1 2 func makeNumber() -> some Numeric { 42 } // static dispatch, concrete type hidden let numbers: [any Numeric] = [1, 2.0, 3.0] // heterogeneous storage Protocols with Self or Associated Types Protocols referencing Self or an associated type in requirements cannot be used as plain existentials without extra information. Reach for: Generics on functions or types: func render<P: View>(_ view: P) -> some View Type erasure wrappers: struct AnyProvider<Item>: Provider { ... } Opaque returns when a single concrete type is guaranteed. Constraint Hygiene Tips Keep constraints close to the API that needs them; avoid lifting all constraints to top-level types. Prefer extension-based conformances to keep core types small and reusable. If a type has many conditional conformances, document the minimal required constraints to avoid surprises for callers. Testing Add focused tests around type-erased wrappers to ensure requirements are forwarded. For APIs relying on constraints, add compile-time checks via unused functions in test targets (e.g., a generic helper that must type-check).
KeyPaths and Pattern Matching (with version cues) How to leverage key paths and pattern matching to write concise, readable Swift. Version Quick Reference Swift 4+: writable key paths, \.property syntax. Swift 5.x+: KeyPath improvements and pattern matching ergonomics. Swift 5.7+: any spelling for existentials can appear with KeyPath constraints. KeyPath Basics Use \Type.property to reference properties without calling them. Great for mapping, sorting, and dependency injection. 1 2 3 4 struct User { let name: String; let age: Int } let names = users.map(\.name) let sorted = users.sorted(by: \.age) // via overload taking a key path For mutation, use WritableKeyPath and ReferenceWritableKeyPath (classes). 1 2 3 func set<Value>(_ keyPath: WritableKeyPath<User, Value>, to value: Value, on user: inout User) { user[keyPath: keyPath] = value } Dynamic Member Lookup Some types expose dynamic members that forward through key paths (e.g., SwiftUI.Binding). You can build your own with @dynamicMemberLookup and subscript overloads taking key paths. Pattern Matching Essentials switch supports case, where clauses, and pattern bindings for enums, optionals, tuples, ranges, and custom patterns. 1 2 3 4 5 6 7 8 switch value { case .success(let data): handle(data) case .failure(let error) where error.isRetriable: retry() case .failure: break } if case / guard case Use to destructure single values without a full switch. 1 2 3 4 if case .failure(let error) = result { print(error) } guard case .success(let payload) = result else { return } process(payload) Optional Patterns Match .some/.none or use if case let x?. 1 if case let value? = optionalValue { print(value) } Tuple and Range Patterns Destructure tuples in switches; match numeric ranges with ... or ..<. 1 2 3 4 5 6 let point = (x: 3, y: 7) switch point { case (0, 0): print("origin") case (1..., 1...): print("quadrant") default: break } Custom Pattern Matching Implement ~= (pattern:value:) to enable custom matching. Keep it lightweight and predictable. 1 2 3 4 5 6 7 struct Prefix { let value: String } func ~=(pattern: Prefix, value: String) -> Bool { value.hasPrefix(pattern.value) } switch "swift-notes" { case Prefix("swift"): print("matches") default: break } Tips Prefer exhaustive switch on enums to catch new cases at compile time. Combine where clauses for readability instead of nesting conditionals. Keep custom patterns simple to avoid surprising control flow.
Memory and Value Semantics (with version cues) ARC basics, retain cycles, copy-on-write, and value vs reference semantics. Version Quick Reference Swift 5.x+: ARC for reference types; standard library uses copy-on-write (CoW) for Array, Dictionary, Set. Swift 5.7+: stricter Sendable checking (behind flags) helps surface thread-safety and aliasing issues. Swift 6+: strict concurrency checking by default; @MainActor/Sendable diagnostics catch unsafe sharing early. ARC Essentials Classes and closures are reference types managed by ARC. Increments on strong references; decrements on release. Avoid retain cycles by breaking strong references in one direction (weak or unowned depending on lifetime guarantees). 1 2 3 4 5 6 final class Controller { var handler: (() -> Void)? func start() { handler = { [weak self] in self?.doWork() } } } weak vs unowned weak: optional, set to nil automatically when the instance deallocates. Use when the reference may outlive the owner. unowned: non-optional, crashes if accessed after deallocation. Use only when lifetimes are strictly tied. Copy-on-Write (CoW) Standard collections are value types with CoW: copying is cheap until mutation. 1 2 3 var a = [1, 2, 3] var b = a // shares storage b.append(4) // triggers copy; `a` remains [1, 2, 3] When building your own CoW types, store reference-backed storage and implement mutating setters that call isKnownUniquelyReferenced. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 struct Buffer { final class Storage { var values: [Int] init(_ values: [Int]) { self.values = values } } private var storage = Storage([]) private mutating func ensureUnique() { if !isKnownUniquelyReferenced(&storage) { storage = Storage(storage.values) } } mutating func append(_ value: Int) { ensureUnique() storage.values.append(value) } } Value vs Reference Semantics Prefer value types (struct/enum) for domain models; they compose better and avoid aliasing bugs. Use classes for shared mutable state, UI objects, or when identity matters. Document ownership: who creates, who retains, and who mutates. Concurrency Considerations CoW reduces accidental sharing across threads, but mutable references inside structs can still race. Mark shared references as Sendable or wrap in actors/locks. @MainActor on UI-bound classes clarifies threading; for data models, prefer pure value types or isolated actors. Testing Add tests to ensure CoW types copy on mutation (check identity before/after mutation). For retain cycles, use weak expectations in tests: create, nil-out strong refs, and assert deallocation occurs.
Observation Macros (@Observable / @Bindable) (iOS 17+) Lightweight SwiftUI observation introduced in iOS 17 / macOS 14. Replaces many ObservableObject boilerplates; still opt-in depending on deployment target. Version Quick Reference iOS 17, macOS 14, watchOS 10, tvOS 17: @Observable and @Bindable. Older OS targets: stick with ObservableObject, @Published, @StateObject/@ObservedObject. Basic Usage Mark a reference type (or actor) with @Observable to synthesize change notifications for stored properties. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Observable final class CounterModel { var count = 0 func increment() { count += 1 } } struct CounterView: View { @State private var model = CounterModel() var body: some View { VStack { Text("\(model.count)") Button("Plus") { model.increment() } } } } No need for ObservableObject or @Published; mutation on observed properties triggers view updates. @Bindable Use @Bindable in child views to get bindings into an @Observable model without manually creating Binding values. 1 2 3 4 5 6 struct DetailView: View { @Bindable var model: CounterModel var body: some View { Stepper("Count", value: $model.count) } } Interop with Existing Patterns You can mix @Observable models with @StateObject when you own the lifetime, or pass them down with @ObservedObject-like semantics using plain references (the model itself performs observation). For legacy targets, keep an ObservableObject wrapper or use conditional compilation: 1 2 3 4 5 #if canImport(Observation) @Observable final class ProfileModel { var name = "" } #else final class ProfileModel: ObservableObject { @Published var name = "" } #endif Concurrency Notes Observation macros work with actors too; the generated conformance handles main-actor isolation if your type is @MainActor. Avoid heavy work in property observers; keep state updates lightweight and move side effects to methods. Testing In previews/tests, mutate properties and assert UI/output changes. For legacy fallback, ensure both code paths stay in sync using small compile-time helpers or conditional tests.
Opaque Types in Swift Swift’s some keyword lets you return a value whose concrete type stays hidden while still preserving type safety. It behaves like the inverse of any: callers know there is a specific type, but they only interact with the protocol requirements that type satisfies. Why Use Opaque Return Types? Hide implementation details while keeping static dispatch and optimizations. Avoid exposing long generic signatures from helper methods. Keep flexibility to swap implementations without breaking API callers. Basic Example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protocol Shape { func area() -> Double } struct Square: Shape { let edge: Double func area() -> Double { edge * edge } } struct Circle: Shape { let radius: Double func area() -> Double { Double.pi * radius * radius } } // Only promise that the result conforms to Shape; callers do not know if it is a Circle or Square. func makeUnitSquare() -> some Shape { Square(edge: 1) } func makeCircle(radius: Double) -> some Shape { Circle(radius: radius) } Opaque types guarantee that each function returns a single concrete type. makeUnitSquare() always yields Square, while makeCircle(radius:) always yields Circle for any radius value. ...
Programmatic UI Source Code Create Component 1 2 3 4 5 6 7 private let titleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.font = .systemFont(ofSize: 22, weight: .bold) label.numberOfLines = 0 return label }() 1 2 3 4 5 6 7 8 9 10 private let downloadButton: UIButton = { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false button.backgroundColor = .red button.setTitle("Download", for: .normal) button.setTitleColor(.white, for: .normal) button.layer.cornerRadius = 8 button.layer.masksToBounds = true return button }() Add component to View 1 2 3 4 5 6 7 8 override func viewDidLoad() { super.viewDidLoad() view.addSubview(titleLabel) view.addSubview(downloadButton) // coming soon :) configureConstraints() } Configure Constraints leading: left | trailing: right ...
Property Wrappers and Result Builders (with version cues) Practical usage of property wrappers and result builders, with version highlights. Version Quick Reference Swift 5.1: property wrappers introduced. Swift 5.4: result builders stabilized (formerly function builders). Swift 5.9+: macros arrive (not covered here); builders/wrappers remain common for DSLs. Swift 6+: stricter concurrency checking; wrappers interacting with concurrency may need Sendable/@MainActor. Property Wrappers Basics Wrap storage/behavior behind a projected value. Use @propertyWrapper on a struct/class/enum. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @propertyWrapper struct Clamped<Value: Comparable> { private var value: Value let range: ClosedRange<Value> init(wrappedValue: Value, _ range: ClosedRange<Value>) { self.range = range self.value = min(max(wrappedValue, range.lowerBound), range.upperBound) } var wrappedValue: Value { get { value } set { value = min(max(newValue, range.lowerBound), range.upperBound) } } } struct Volume { @Clamped(0...100) var level = 50 } Access with _level to reach the storage, $level for the projected value (customizable via projectedValue). Common SwiftUI Wrappers (recap) @State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject, @AppStorage, @SceneStorage. Remember: choose based on ownership/lifetime (see swiftui-state.md). Result Builders Builders collect expressions into a composed result (e.g., SwiftUI ViewBuilder). 1 2 3 4 5 6 7 8 9 10 11 @resultBuilder struct StringListBuilder { static func buildBlock(_ components: String...) -> [String] { components } } @StringListBuilder func makeStrings() -> [String] { "one" if Bool.random() { "two" } for i in 0..<2 { "loop \(i)" } } Builders support buildBlock, buildOptional, buildEither, buildArray, and optionally buildFinalResult. Use @ViewBuilder/@SceneBuilder (iOS 13+) and @ToolbarContentBuilder (iOS 14+) in SwiftUI. Concurrency Considerations If wrapper storage crosses actors/threads, consider Sendable and isolation. For UI wrappers, mark with @MainActor when needed. Avoid heavy work in getters/setters of wrappers; keep them lightweight to avoid surprising costs. Testing For wrappers, test boundary cases on the wrapped/projection values. For builders, add small functions that must type-check to catch regressions when changing builder signatures.
Protocols, Existentials, and Composition (with version cues) Practical patterns for using protocols, any vs some, and type erasure. Version Quick Reference Swift 5.6+: any keyword required for existential types. Swift 5.7: primary associated types improve existential ergonomics; better diagnostics for Self and associated-type constraints. Swift 6+: stricter Sendable/actor-isolation checks make any vs some choices more visible. any vs some any Protocol: type-erased box; dynamic dispatch; multiple conformers can coexist (heterogeneous containers, stored properties). some Protocol: concrete type stays hidden but fixed per function; static dispatch; great for return types when a single conformer is guaranteed. 1 2 func makeRow() -> some View { Text("Hi") } // fixed concrete type let rows: [any View] = [Text("Hi"), Image(systemName: "star")] // heterogeneous Self Requirements and Associated Types Protocol requirements mentioning Self or an associated type block plain existential use. Reach for: Generics on the function/type (func render<P: View>(_ view: P) -> some View) Type erasure wrappers (e.g., AnySequence, AnyPublisher) Opaque returns (some) when a single conformer is stable. Type Erasure Pattern Wrap a protocol with associated types in a box to regain existential ergonomics. 1 2 3 4 5 6 7 8 9 10 11 12 protocol DataProvider { associatedtype Item func items() -> [Item] } struct AnyDataProvider<Item>: DataProvider { private let _items: () -> [Item] init<P: DataProvider>(_ provider: P) where P.Item == Item { _items = provider.items } func items() -> [Item] { _items() } } let providers: [AnyDataProvider<String>] = [AnyDataProvider(LocalProvider())] Protocol Composition Combine requirements with &: any A & B. For some, composition still promises one concrete type that conforms to all listed protocols. 1 2 3 4 protocol Displayable { var title: String { get } } protocol Loadable { func load() async throws } func makeFeature() -> some Displayable & Loadable { Feature() } Extensions vs Inheritance Prefer protocol extensions to add shared behavior without forcing inheritance. Keep inheritance shallow; compose small protocols instead. Avoid over-broad “god protocols.” Split into role-focused protocols and recompose at use sites. Testing and Diagnostics When using type erasure, add small tests to ensure forwarding works (items() returns expected values). If you need compile-time coverage, add helper functions in tests that must type-check to catch regressions in constraints.
How to use RealmSwift? What is Realm Swift? Realm Swift is an easy to use alternative to SQLite and Core Data that makes persisting, querying, and syncing data as simple as working directly with native Swift objects. Visit to RealmSwift page 👆 Quick Start Initilation realm - Appdelegate.swift 1 2 3 4 5 6 7 8 9 10 11 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // realm db location // print(Realm.Configuration.defaultConfiguration.fileURL) // checking connection do { _ = try Realm() } catch { print("Error initialising new realm, \(error)") } return true } Define your models like regular Swift classes ...