<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Divyesh Vekariya on Medium]]></title>
        <description><![CDATA[Stories by Divyesh Vekariya on Medium]]></description>
        <link>https://medium.com/@dkvekariya?source=rss-6317b0b805bf------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*Zpy6MH_OYXnmPOzRQZUifQ.png</url>
            <title>Stories by Divyesh Vekariya on Medium</title>
            <link>https://medium.com/@dkvekariya?source=rss-6317b0b805bf------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 03 Nov 2026 09:44:22 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@dkvekariya/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Swift Actors: Safe Shared State in Concurrent Code]]></title>
            <link>https://dkvekariya.medium.com/swift-actors-safe-shared-state-in-concurrent-code-eb335ee63375?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/eb335ee63375</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 30 Oct 2026 14:11:01 GMT</pubDate>
            <atom:updated>2026-10-30T14:11:01.722Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Data races are silent. They corrupt state without crashing immediately. Actors make them impossible.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yUnLqA7V5X20v8b1Nh5n5g.png" /></figure><h3>The Problem Actors Solve</h3><p><a href="https://medium.com/p/9832bc47fb53">Async/await</a> makes asynchronous code readable. It does not make it safe.</p><p>Consider two concurrent tasks reading and writing the same property on a class:</p><pre>class Counter {<br>    var value = 0<br><br>    func increment() {<br>        value += 1<br>    }<br>}<br><br>let counter = Counter()<br>Task { counter.increment() }<br>Task { counter.increment() }</pre><p>Both tasks run concurrently. Both read value, both add 1, both write back. If they interleave at exactly the wrong moment, both read 0, both write 1, and the result is 1 instead of 2. The data is silently corrupted. No crash. No warning. Just a wrong number.</p><p>This is a <strong>data race</strong>. In production apps with real concurrency, they are inevitable without a protection mechanism.</p><p>Actors are that mechanism.</p><h3>What Is an Actor?</h3><p>An actor is a <a href="https://dkvekariya.medium.com/f7a1fd4bd47c">reference type</a>, like a class, with one critical difference: only one task can access its mutable state at a time. The Swift runtime enforces this automatically.</p><pre>actor Counter {<br>    var value = 0<br><br>    func increment() {<br>        value += 1  // safe - only one caller at a time<br>    }<br><br>    func currentValue() -&gt; Int {<br>        value<br>    }<br>}</pre><p>Declare it with actor instead of class. That single keyword makes all mutable state inside it serialized. No locks. No queues. No manual synchronization.</p><h3>Accessing an Actor</h3><p>Because actor methods can only run one at a time, calling them from outside requires await. The call suspends until the actor is available.</p><pre>let counter = Counter()<br><br>Task {<br>    await counter.increment()<br>    let value = await counter.currentValue()<br>    print(value)  // always correct, never a data race<br>}<br><br>Task {<br>    await counter.increment()<br>}</pre><p>The await is not waiting for a network call here. It is waiting for the actor to be free. If another task is currently executing inside the actor, this one suspends until the actor finishes and hands control over.</p><h3>Actor Isolation</h3><p>Properties and methods inside an actor are <strong>isolated</strong>. Accessing them from outside always requires await.</p><pre>actor ImageCache {<br>    private var cache: [String: UIImage] = [:]<br><br>    func store(_ image: UIImage, for key: String) {<br>        cache[key] = image<br>    }<br>    func retrieve(for key: String) -&gt; UIImage? {<br>        cache[key]<br>    }<br>}<br><br>let cache = ImageCache()<br>// From async context<br>let image = await cache.retrieve(for: &quot;profile_pic&quot;)<br>await cache.store(downloadedImage, for: &quot;profile_pic&quot;)</pre><p>The cache dictionary is never touched by two tasks simultaneously. The actor guarantees it.</p><h3>nonisolated: Opting Out of Isolation</h3><p>Some methods do not touch mutable state and do not need isolation. Mark them nonisolated to call them without await.</p><pre>actor UserSession {<br>    var token: String<br>    let userID: String  // constant — safe to access without isolation<br><br>    init(token: String, userID: String) {<br>        self.token = token<br>        self.userID = userID<br>    }<br>    nonisolated func sessionDescription() -&gt; String {<br>        &quot;Session for user \(userID)&quot;  // only reads a constant<br>    }<br>}<br>let session = UserSession(token: &quot;tok_abc&quot;, userID: &quot;usr_001&quot;)<br>// No await needed<br>print(session.sessionDescription())</pre><p>nonisolated is useful for methods that only read constants, conform to protocols with synchronous requirements, or do pure computation with no shared state.</p><h3>MainActor: The Actor for UI Work</h3><p>@MainActor is a global actor built into Swift. Every method marked with it runs on the main thread. It is the replacement for DispatchQueue.main.async.</p><pre>@MainActor<br>class FeedViewModel: ObservableObject {<br>    @Published var posts: [Post] = []<br>    @Published var isLoading = false<br><br>    func loadFeed() async {<br>        isLoading = true<br>        defer { isLoading = false }<br>        do {<br>            // This await suspends off the main thread<br>            let fetched = try await PostService.shared.fetchPosts()<br>            // Resuming here is guaranteed to be on the main thread<br>            posts = fetched<br>        } catch {<br>            print(&quot;Load failed: \(error)&quot;)<br>        }<br>    }<br>}</pre><p>The entire class is main-actor-isolated. Every property access and every method call is thread-safe for UI work without a single DispatchQueue call anywhere.</p><h3>Sendable: Crossing Concurrency Boundaries Safely</h3><p>When you pass data between actors or tasks, Swift needs to know the data is safe to share. Types that are safe to send across concurrency boundaries conform to Sendable.</p><pre>// Structs with Sendable properties are automatically Sendable<br>struct Message: Sendable {<br>    let id: UUID<br>    let text: String<br>    let sentAt: Date<br>}<br><br>// Classes must be manually marked and are only safe if they protect their state<br>final class UserToken: @unchecked Sendable {<br>    private let lock = NSLock()<br>    private var _value: String<br>    init(_ value: String) { _value = value }<br>    var value: String {<br>        lock.withLock { _value }<br>    }<br>}</pre><p>Value types like structs are Sendable by default when all their stored properties are Sendable. <a href="https://dkvekariya.medium.com/f7a1fd4bd47c">Classes</a> require explicit annotation and manual safety guarantees.</p><p>The compiler warns you when you try to send non-Sendable types across concurrency boundaries, catching potential data races at build time.</p><h3>Actor Reentrancy</h3><p>Actors are reentrant. When an actor suspends at an await inside one of its methods, another task can enter the actor during that suspension.</p><pre>actor DataStore {<br>    var items: [String] = []<br><br>    func addItem(_ item: String) async {<br>        // Another task can run here while this one is suspended<br>        let validated = await validate(item)<br>        // items might have changed while we were suspended<br>        items.append(validated)<br>    }<br>}</pre><p>This is intentional. Non-reentrant actors would deadlock. But it means you should not assume state is unchanged across an await inside an actor. Check state again after every suspension if your logic depends on it.</p><h3>Real-World Pattern: Thread-Safe Cache</h3><pre>actor NetworkCache {<br>    private var cache: [URL: Data] = [:]<br>    private var inFlightRequests: [URL: Task&lt;Data, Error&gt;] = [:]<br><br>    func data(for url: URL) async throws -&gt; Data {<br>        // Return cached data immediately if available<br>        if let cached = cache[url] {<br>            return cached<br>        }<br>        // Reuse an in-flight request for the same URL<br>        if let existing = inFlightRequests[url] {<br>            return try await existing.value<br>        }<br>        // Start a new request<br>        let task = Task&lt;Data, Error&gt; {<br>            let (data, _) = try await URLSession.shared.data(from: url)<br>            return data<br>        }<br>        inFlightRequests[url] = task<br>        do {<br>            let data = try await task.value<br>            cache[url] = data<br>            inFlightRequests[url] = nil<br>            return data<br>        } catch {<br>            inFlightRequests[url] = nil<br>            throw error<br>        }<br>    }<br>}</pre><p>This cache deduplicates concurrent requests for the same URL, stores results, and handles errors cleanly. Without actors, implementing this correctly requires explicit locking and is easy to get wrong. With an actor, the isolation guarantee does the heavy lifting.</p><h3>Interview Questions</h3><p><strong>Q: What is an actor in Swift and how does it prevent data races?</strong></p><p>An actor is a <a href="https://dkvekariya.medium.com/f7a1fd4bd47c">reference type</a> that serializes access to its mutable state. Only one task can execute inside an actor at a time. The Swift compiler enforces this: accessing an actor’s properties or methods from outside requires await, which suspends the caller until the actor is free. This makes it structurally impossible for two tasks to read and write the same mutable state simultaneously, eliminating data races without manual locking.</p><p><strong>Q: What is the difference between an actor and a class with a lock?</strong></p><p>Both protect shared mutable state from concurrent access. A class with a manual lock puts the burden on the developer to lock correctly, unlock in all paths including errors, and avoid deadlocks. Actors move this enforcement to the compiler. You cannot accidentally access actor state without await. The compiler catches violations at build time. Actors are also reentrant by design, which avoids deadlocks that explicit locks can cause when a function tries to acquire a lock it already holds.</p><h3>Summary</h3><ul><li>Data races happen when two tasks read and write the same mutable state concurrently without synchronization.</li><li>An actor serializes access to its mutable state. Only one task runs inside it at a time.</li><li>Accessing actor state from outside requires await, which suspends until the actor is available.</li><li>nonisolated methods opt out of isolation for pure computation and constant access.</li><li>@MainActor is a global actor that ensures code runs on the main thread.</li><li>Actor reentrancy means state can change across an await inside an actor. Check state again after suspension when it matters.</li><li>Sendable marks types safe to pass across concurrency boundaries. Structs are Sendable by default.</li><li>The compiler enforces concurrency safety at build time, not runtime.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Convert this class to an actor and fix all the call sites to use await:</li></ol><pre>class ScoreTracker {<br>    var highScore = 0<br>    var totalGames = 0<br><br>    func recordScore(_ score: Int) {<br>        totalGames += 1<br>        if score &gt; highScore { highScore = score }<br>    }<br>}</pre><p>Show that two concurrent Tasks updating the score are now safe.</p><ol><li><strong>Intermediate:</strong> Build a thread-safe RateLimiter actor that tracks how many requests have been made in the last 60 seconds. Add a canMakeRequest() -&gt; Bool method and a recordRequest() method. Use it to guard API calls in a view model and show how @MainActor on the view model composes correctly with the actor-isolated rate limiter.</li><li><strong>Advanced:</strong> Implement a DownloadManager actor that manages up to 3 concurrent downloads. Queues additional requests beyond that limit. Provides progress: Double per download URL. Notifies a @MainActor delegate when each download completes. Handle cancellation cleanly so cancelling one download does not affect others in the queue.</li></ol><h3>What’s Next</h3><p><strong>Article 20: Swift Property Wrappers: @State, @Binding, @Published, and Building Your Own</strong></p><p>Actors protect shared state at the runtime level. Property wrappers manage state at the declaration level. @State, @Binding, @Published, @AppStorage, @EnvironmentObject — every SwiftUI developer uses these daily. Understanding what they actually do, and how to build your own, is what separates developers who fight SwiftUI from developers who work with it.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If actors just replaced a mental model built on DispatchQueue and locks, tap 👏 up to 50 times. It helps this series reach developers still writing thread-unsafe code without knowing it.</strong></p><p><strong>Follow me</strong> so Article 20 lands in your feed automatically. Property wrappers are next and they unlock a completely different way to manage state.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eb335ee63375" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Async Await: Modern Concurrency Without the Callback Chaos]]></title>
            <link>https://dkvekariya.medium.com/swift-async-await-modern-concurrency-without-the-callback-chaos-9832bc47fb53?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/9832bc47fb53</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 23 Oct 2026 14:11:01 GMT</pubDate>
            <atom:updated>2026-10-23T14:11:01.950Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Completion handlers were a workaround. Async/await is the solution.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6sYLz3SyENay3I1EibECxw.png" /></figure><h3>The Problem Async/Await Solves</h3><p>Before Swift 5.5, every asynchronous operation used <a href="https://dkvekariya.medium.com/91d441e21f24">completion handlers</a>. Network call? Callback. Parse the result? Another callback. Update the UI? Dispatch back to the main thread in yet another callback.</p><pre>// The old way — callback pyramid<br>func loadUserProfile(id: String) {<br>    fetchUser(id: id) { result in<br>        switch result {<br>        case .success(let user):<br>            fetchPosts(for: user) { result in<br>                switch result {<br>                case .success(let posts):<br>                    fetchComments(for: posts.first) { result in<br>                        switch result {<br>                        case .success(let comments):<br>                            DispatchQueue.main.async {<br>                                self.updateUI(user: user, posts: posts, comments: comments)<br>                            }<br>                        case .failure(let error):<br>                            self.showError(error)<br>                        }<br>                    }<br>                case .failure(let error):<br>                    self.showError(error)<br>                }<br>            }<br>        case .failure(let error):<br>            self.showError(error)<br>        }<br>    }<br>}</pre><p>Three levels of nesting for three sequential operations. <a href="https://dkvekariya.medium.com/897fb535f805">Error handling </a>is duplicated at every level. Thread management is manual. This is not an extreme example. This is a typical profile screen.</p><p>Async/await collapses all of it.</p><h3>The Same Code With Async/Await</h3><pre>func loadUserProfile(id: String) async throws {<br>    let user = try await fetchUser(id: id)<br>    let posts = try await fetchPosts(for: user)<br>    let comments = try await fetchComments(for: posts.first)<br>    updateUI(user: user, posts: posts, comments: comments)<br>}</pre><p>Same operations. Same <a href="https://dkvekariya.medium.com/897fb535f805">error handling</a>. Reads like synchronous code. The compiler and Swift runtime handle all the thread management.</p><h3>How Async Functions Work</h3><p>Mark a function with async to indicate it can suspend execution without blocking a thread.</p><pre>func fetchUser(id: String) async throws -&gt; User {<br>    let url = URL(string: &quot;https://api.myapp.com/users/\(id)&quot;)!<br>    let (data, response) = try await URLSession.shared.data(from: url)<br><br>    guard let httpResponse = response as? HTTPURLResponse,<br>          httpResponse.statusCode == 200 else {<br>        throw NetworkError.serverError<br>    }<br><br>    return try JSONDecoder().decode(User.self, from: data)<br>}</pre><p>async in the signature tells callers this function suspends. await at the call site marks where suspension can happen. When the function hits await, Swift suspends it, frees the thread for other work, and resumes when the awaited operation completes.</p><p>The thread is not blocked. It is not sleeping. It is doing other work.</p><h3>Calling Async Functions</h3><p>You can only call async functions from an async context. In a SwiftUI view or UIViewController, start a Task:</p><pre>// SwiftUI<br>.onAppear {<br>    Task {<br>        do {<br>            user = try await fetchUser(id: &quot;usr_001&quot;)<br>        } catch {<br>            errorMessage = error.localizedDescription<br>        }<br>    }<br>}<br><br>// UIKit<br>override func viewDidLoad() {<br>    super.viewDidLoad()<br>    Task {<br>        do {<br>            let user = try await fetchUser(id: &quot;usr_001&quot;)<br>            updateUI(with: user)<br>        } catch {<br>            showError(error)<br>        }<br>    }<br>}</pre><p>Task creates a new asynchronous unit of work. It bridges the synchronous UIKit/SwiftUI world into the async world.</p><h3>async let: Parallel Execution</h3><p>Sequential await calls run one after another. When operations are independent, run them in parallel with async let.</p><pre>// Sequential — total time = A + B + C<br>func loadDashboard() async throws -&gt; Dashboard {<br>    let user = try await fetchUser(id: currentUserID)<br>    let feed = try await fetchFeed()<br>    let notifications = try await fetchNotifications()<br><br>    return Dashboard(user: user, feed: feed, notifications: notifications)<br>}<br><br>// Parallel - total time = max(A, B, C)<br>func loadDashboard() async throws -&gt; Dashboard {<br>    async let user = fetchUser(id: currentUserID)<br>    async let feed = fetchFeed()<br>    async let notifications = fetchNotifications()<br><br>    return try await Dashboard(<br>        user: user,<br>        feed: feed,<br>        notifications: notifications<br>    )<br>}<br></pre><p>async let launches all three requests simultaneously. The await at the end waits for all of them. If your dashboard loaded in 1.5 seconds before, this version might load it in 0.5 seconds with no extra code.</p><h3>Async Sequences</h3><p>for await iterates over values that arrive asynchronously over time.</p><pre>func streamLiveScores() async throws {<br>    let url = URL(string: &quot;https://api.sports.com/live&quot;)!<br><br>    for try await score in URLSession.shared.bytes(from: url).lines {<br>        updateScoreBoard(with: score)<br>    }<br>}</pre><p>Each iteration suspends until the next value arrives, without blocking any thread. This replaces long-polling patterns and WebSocket callback chains cleanly.</p><h3>Structured Concurrency with TaskGroup</h3><p>When the number of parallel operations is dynamic, use TaskGroup.</p><pre>func fetchAllProfiles(ids: [String]) async throws -&gt; [User] {<br>    try await withThrowingTaskGroup(of: User.self) { group in<br>        for id in ids {<br>            group.addTask {<br>                try await fetchUser(id: id)<br>            }<br>        }<br>        <br>        var users: [User] = []<br>        for try await user in group {<br>            users.append(user)<br>        }<br>        return users<br>    }<br>}</pre><p>Each ID gets its own task. All tasks run in parallel. Results are collected as they complete. The group handles cancellation and error propagation automatically.</p><h3>Cancellation</h3><p>Tasks can be cancelled. Check Task.isCancelled to exit early from long operations.</p><pre>func processImages(_ urls: [URL]) async throws -&gt; [UIImage] {<br>    var images: [UIImage] = []<br><br>    for url in urls {<br>        try Task.checkCancellation()  // throws CancellationError if cancelled<br>        let image = try await downloadImage(from: url)<br>        images.append(image)<br>    }<br>    return images<br>}</pre><p>When the calling task is cancelled (user navigates away, for example), checkCancellation throws and the function exits cleanly. No lingering work, no wasted network calls.</p><h3>MainActor: Thread Safety for UI Updates</h3><p>UI updates must happen on the main thread. @MainActor enforces this at compile time.</p><pre>@MainActor<br>class UserViewModel: ObservableObject {<br>    @Published var user: User?<br>    @Published var isLoading = false<br><br>func loadUser(id: String) async {<br>        isLoading = true<br>        defer { isLoading = false }<br>        do {<br>            user = try await fetchUser(id: id)  // suspends off main thread<br>            // automatically resumes on main thread - @MainActor guarantees it<br>        } catch {<br>            print(&quot;Error: \(error)&quot;)<br>        }<br>    }<br>}</pre><p>The await suspends off the main thread while the network request runs. When it resumes, @MainActor guarantees it is back on the main thread before touching user or isLoading. No DispatchQueue.main.async { } needed.</p><h3>Real-World Pattern: Repository With Async/Await</h3><pre>protocol UserRepository {<br>    func fetchUser(id: String) async throws -&gt; User<br>    func updateUser(_ user: User) async throws -&gt; User<br>    func deleteUser(id: String) async throws<br>}<br><br>struct LiveUserRepository: UserRepository {<br>    private let client: APIClient<br>    func fetchUser(id: String) async throws -&gt; User {<br>        try await client.get(&quot;/users/\(id)&quot;)<br>    }<br>    func updateUser(_ user: User) async throws -&gt; User {<br>        try await client.put(&quot;/users/\(user.id)&quot;, body: user)<br>    }<br>    func deleteUser(id: String) async throws {<br>        try await client.delete(&quot;/users/\(id)&quot;)<br>    }<br>}<br><br>@MainActor<br>class UserViewModel: ObservableObject {<br>    @Published var user: User?<br>    private let repository: UserRepository<br>    init(repository: UserRepository = LiveUserRepository(client: .shared)) {<br>        self.repository = repository<br>    }<br>    func load(id: String) async {<br>        do {<br>            user = try await repository.fetchUser(id: id)<br>        } catch {<br>            print(error)<br>        }<br>    }<br>}</pre><p>Protocol-based repository, async throughout, @MainActor for safe UI updates, dependency-injectable for testing. This is the pattern that scales.</p><h3>Interview Questions</h3><p><strong>Q: How does async/await differ from completion handlers in Swift?</strong></p><p>Completion handlers use <a href="https://dkvekariya.medium.com/91d441e21f24">closures</a> called back when work finishes. They lead to nested callbacks, duplicated error handling, and manual thread management. Async/await lets asynchronous code look and read like synchronous code. The compiler and Swift runtime manage suspension and resumption. <a href="https://dkvekariya.medium.com/897fb535f805">Error handling</a> uses the same try/catch as synchronous code. Thread management is handled by actors and @MainActor. The result is code that is dramatically easier to read, write, and debug.</p><p><strong>Q: What is the difference between sequential await and async let?</strong></p><p>Sequential await calls execute one after another. Each call waits for the previous one to finish before starting. async let starts multiple async operations simultaneously. The final await waits for all of them to complete. Use sequential await when each result depends on the previous one. Use async let when operations are independent and can run in parallel, reducing total execution time to the duration of the longest operation rather than the sum of all.</p><h3>Summary</h3><ul><li>async marks a function that can suspend without blocking a thread.</li><li>await marks where suspension happens and the runtime may do other work.</li><li>Task bridges synchronous code into an async context from UIKit and SwiftUI.</li><li>Sequential await runs operations one after another.</li><li>async let runs independent operations in parallel.</li><li>for await iterates over async sequences that deliver values over time.</li><li>TaskGroup coordinates a dynamic number of parallel tasks.</li><li>Task.checkCancellation() exits cleanly when a task is cancelled.</li><li>@MainActor guarantees UI updates happen on the main thread without manual dispatching.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Convert this <a href="https://dkvekariya.medium.com/91d441e21f24">completion-handler</a> function to async/await:</li></ol><pre>func fetchQuote(completion: @escaping (Result&lt;String, Error&gt;) -&gt; Void) {<br>    URLSession.shared.dataTask(with: URL(string: &quot;https://api.quotable.io/random&quot;)!) { data, _, error in<br>        if let error = error { completion(.failure(error)); return }<br>        let quote = String(data: data!, encoding: .utf8) ?? &quot;&quot;<br>        completion(.success(quote))<br>    }.resume()<br>}</pre><ol><li><strong>Intermediate:</strong> Build a ImageLoader class that fetches three images in parallel using async let, falls back to a placeholder if any individual image fails (without failing the whole operation), and publishes the results on the main thread via @MainActor.</li><li><strong>Advanced:</strong> Implement a RateLimitedTaskGroup that runs a dynamic list of async tasks but limits concurrency to a maximum of N simultaneous tasks at any time. Use TaskGroup and a semaphore-equivalent mechanism in Swift Concurrency. Show it processing 20 API calls with a concurrency limit of 5.</li></ol><h3>What’s Next</h3><p><strong>Article 19: Swift Actors: Safe Shared State in Concurrent Code</strong></p><p>Async/await handles the flow of asynchronous work. Actors handle the safety of shared mutable state across that work. Without actors, two concurrent tasks reading and writing the same property is a data race. With actors, it is impossible. This is one of the most important concurrency concepts for building stable iOS apps.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If async/await just made your network code feel like a breath of fresh air, tap 👏 up to 50 times and do 🔁. It helps this series reach developers still buried in completion handler pyramids.</strong></p><p><strong>Follow me</strong> so Article 19 lands in your feed automatically. Actors are next and they complete the Swift Concurrency picture.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9832bc47fb53" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Practical Guide to Migrating from RxSwift to AsyncSequence and Observable]]></title>
            <link>https://dkvekariya.medium.com/a-practical-guide-to-migrating-from-rxswift-to-asyncsequence-and-observable-fb8e886e0f1e?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/fb8e886e0f1e</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[rxswift]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ios-development]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Tue, 20 Oct 2026 07:31:01 GMT</pubDate>
            <atom:updated>2026-10-20T07:31:01.635Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>What replaces </em><em>BehaviorRelay, </em><em>DisposeBag, </em><em>flatMapLatest and friends in modern Swift, and what doesn&#39;t have a replacement yet.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CT1pMUz8OOpb0M2oalMC4w.png" /><figcaption>A Practical Guide to Migrating from RxSwift to AsyncSequence and Observable Cover Image</figcaption></figure><p>For years, RxSwift was the answer to a simple question: how do I react to things that change over time? Network responses, user input, notifications, timers and UI state all became streams.</p><p>Swift has since grown its own answers. async/await and AsyncSequence handle asynchronous work and event streams. The @Observable macro handles UI state. Structured concurrency handles cancellation and lifetime.</p><p>So can you replace RxSwift with them? <strong>For most apps, mostly yes. But it’s not a one-to-one swap</strong>, and knowing where it isn’t saves a lot of pain. This guide walks through it as “this replaces that”, with code.</p><h3>The big picture</h3><p>RxSwift did three jobs at once, and each now has a native replacement:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qaOL-5sENuMlixxffVY3Vw.png" /><figcaption>What RxSwift did</figcaption></figure><p>Three things don’t map cleanly: sharing one source between many subscribers (share()), a few niche operators like withLatestFrom, and RxCocoa&#39;s UIKit bindings. I&#39;ll cover those near the end.</p><h4>Requirements</h4><p>@Observable comes from the Observation framework, introduced in iOS 17 with Swift 5.9. If you still support iOS 16, you can&#39;t use it. Stay on ObservableObject and @Published for state, but you can still adopt async/await for the async parts.</p><p>Swift Async Algorithms is a separate Swift package maintained by Apple. You add it as a dependency; it isn’t part of the standard library.</p><h4>Cheat sheet: types</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*amL-sHXPH0ZAmAVuvJhTow.png" /><figcaption>Cheat sheet: types</figcaption></figure><h4>Cheat sheet: operators</h4><p>Built into AsyncSequence:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n4QkgbMBEj-vnL9OBS-6jQ.png" /><figcaption>Cheat sheet Operator built into AsyncSequence</figcaption></figure><p>From the Swift Async Algorithms package:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-6EDOTzyFh99WCbYWxlkgw.png" /><figcaption>Cheat sheet Operator AsyncAlgorithms</figcaption></figure><p>From the language itself:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l-ZgDmJ-IdESGSCd4gL8vQ.png" /><figcaption>Cheat sheet Operator from the Language itself</figcaption></figure><h3>Part 1: State. From BehaviorRelay and Driver to @Observable</h3><p>Here’s a typical RxSwift view model:</p><pre>final class ProfileViewModel {<br>    private let disposeBag = DisposeBag()<br><br>    let name = BehaviorRelay&lt;String&gt;(value: &quot;&quot;)<br>    let isLoading = BehaviorRelay&lt;Bool&gt;(value: false)<br>    let errorMessage = PublishRelay&lt;String&gt;()<br>    init(api: API) {<br>        isLoading.accept(true)<br>        api.fetchProfile()                       // Single&lt;Profile&gt;<br>            .observe(on: MainScheduler.instance)<br>            .subscribe(<br>                onSuccess: { [weak self] profile in<br>                    self?.name.accept(profile.name)<br>                    self?.isLoading.accept(false)<br>                },<br>                onFailure: { [weak self] error in<br>                    self?.errorMessage.accept(error.localizedDescription)<br>                    self?.isLoading.accept(false)<br>                }<br>            )<br>            .disposed(by: disposeBag)<br>    }<br>}</pre><p>And the modern version:</p><pre>import Observation<br><br>@MainActor<br>@Observable<br>final class ProfileViewModel {<br>    var name = &quot;&quot;<br>    var isLoading = false<br>    var errorMessage: String?<br><br>    @ObservationIgnored private let api: API<br><br>    init(api: API) {<br>        self.api = api<br>    }<br><br>    func load() async {<br>        isLoading = true<br>        defer { isLoading = false }<br>        do {<br>            let profile = try await api.fetchProfile()<br>            name = profile.name<br>        } catch {<br>            errorMessage = error.localizedDescription<br>        }<br>    }<br>}</pre><p>What changed:</p><ul><li>There’s no DisposeBag, no [weak self], no .accept() and no observe(on:). @MainActor takes care of threading.</li><li>BehaviorRelay&lt;T&gt; is now a plain var. @Observable tracks which properties a view actually reads, so only views that read a changed property are invalidated.</li><li>A one-off event like an error toast becomes optional state (as above), or an AsyncStream if you really need event semantics.</li><li>@ObservationIgnored opts a property out of tracking. It&#39;s useful for dependencies that never change.</li><li>@Observable works on classes only.</li></ul><h4>The SwiftUI side</h4><pre>struct ProfileView: View {<br>    @State private var viewModel = ProfileViewModel(api: .live)<br><br>    var body: some View {<br>        VStack {<br>            if viewModel.isLoading { ProgressView() }<br>            Text(viewModel.name)<br>        }<br>        .task { await viewModel.load() }<br>    }<br>}</pre><p>The property wrappers change too:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*92ef9EPGmK0V0nn0nHP8Ng.png" /></figure><p>For controls that need bindings, like a TextField, use @Bindable:</p><pre>struct SearchView: View {<br>    @State private var viewModel = SearchViewModel(api: .live)<br><br>    var body: some View {<br>        @Bindable var viewModel = viewModel<br>        TextField(&quot;Search&quot;, text: $viewModel.query)<br>    }<br>}</pre><h3>Part 2: The classic search box. flatMapLatest and debounce</h3><p>Nothing shows the shift in thinking better than search-as-you-type. In RxSwift:</p><pre>query<br>    .debounce(.milliseconds(300), scheduler: MainScheduler.instance)<br>    .distinctUntilChanged()<br>    .flatMapLatest { api.search($0).catchAndReturn([]) }<br>    .asDriver(onErrorJustReturn: [])<br>    .drive(results)<br>    .disposed(by: disposeBag)</pre><p>With @Observable and .task(id:):</p><pre>@MainActor<br>@Observable<br>final class SearchViewModel {<br>    var query = &quot;&quot;<br>    private(set) var results: [Item] = []<br><br>    @ObservationIgnored private let api: API<br><br>    init(api: API) { self.api = api }<br><br>    func search() async {<br>        let q = query.trimmingCharacters(in: .whitespaces)<br>        guard !q.isEmpty else { results = []; return }<br>        do {<br>            let items = try await api.search(q)<br>            if !Task.isCancelled { results = items }<br>        } catch {<br>            if !Task.isCancelled { results = [] }<br>        }<br>    }<br>}<br><br>struct SearchView: View {<br>    @State private var viewModel = SearchViewModel(api: .live)<br><br>    var body: some View {<br>        @Bindable var viewModel = viewModel<br><br>        List(viewModel.results) { item in Text(item.title) }<br>            .searchable(text: $viewModel.query)<br>            .task(id: viewModel.query) {<br>                do {<br>                    try await Task.sleep(for: .milliseconds(300))<br>                    await viewModel.search()<br>                } catch { /* cancelled while debouncing */ }<br>            }<br>    }<br>}</pre><p>Why this works:</p><ul><li>.task(id:) cancels the running task and starts a new one whenever the id changes. That&#39;s exactly what flatMapLatest does.</li><li>Sleeping first and working second gives you debounce. If the user types again, the sleep throws a cancellation error and the search never fires.</li><li>distinctUntilChanged comes for free, because the task only restarts when the id value actually changes.</li></ul><p>Outside SwiftUI, hold the task yourself:</p><pre>private var searchTask: Task&lt;Void, Never&gt;?<br><br>func queryChanged(_ text: String) {<br>    searchTask?.cancel()<br>    searchTask = Task { [weak self] in<br>        try? await Task.sleep(for: .milliseconds(300))<br>        guard !Task.isCancelled else { return }<br>        await self?.search(text)<br>    }<br>}</pre><h3>Part 3: Streams. From Observable to AsyncSequence</h3><p><strong>Consuming a stream</strong> replaces subscribe with a for await loop:</p><pre>Task {<br>    for await note in NotificationCenter.default.notifications(named: UIApplication.didBecomeActiveNotification) {<br>        print(note)<br>    }<br>}</pre><p>The loop ends when the sequence finishes or the surrounding task is cancelled. There’s no DisposeBag, because the task&#39;s lifetime is the subscription.</p><p><strong>Creating a stream</strong> replaces Observable.create:</p><pre>func locationUpdates() -&gt; AsyncStream&lt;CLLocation&gt; {<br>    AsyncStream { continuation in<br>        let manager = LocationManagerWrapper { location in<br>            continuation.yield(location)<br>        }<br>        manager.start()<br><br>        continuation.onTermination = { _ in<br>            manager.stop()<br>        }<br>    }<br>}</pre><p>LocationManagerWrapper stands in for your own wrapper around the delegate API. onTermination plays the role of the cleanup block in Disposables.create. Use AsyncThrowingStream if the source can fail.</p><p><strong>Subjects</strong> become a stream paired with its continuation:</p><pre>let (stream, continuation) = AsyncStream.makeStream(of: Int.self)<br><br>continuation.yield(1)<br>continuation.yield(2)<br>continuation.finish()<br><br>for await value in stream { print(value) }</pre><p><strong>Combining streams</strong> uses Swift Async Algorithms:</p><pre>import AsyncAlgorithms<br><br>for await (user, settings) in combineLatest(userStream, settingsStream) {<br>    render(user, settings)<br>}<br><br>for await value in merge(streamA, streamB) {<br>    handle(value)<br>}</pre><p><strong>Parallel one-shot calls</strong>, the old Observable.zip of two Singles, are just async let:</p><pre>async let profile = api.fetchProfile()<br>async let posts = api.fetchPosts()<br>let (p, ps) = try await (profile, posts)</pre><h3>Part 4: Watching an @Observable property as a stream</h3><p>A common Rx habit is subscribing to a single property. With @Observable, properties aren&#39;t streams by default.</p><p>Inside SwiftUI you don’t need to do anything. Reading a property in body is the subscription.</p><p>Outside SwiftUI, you have two options:</p><ul><li><strong>withObservationTracking</strong> works back to iOS 17, but it only fires once per registration. You have to re-register after every change.</li><li><strong>Observations</strong> arrived with Swift 6.2 (proposal SE-0475) and is available from iOS 26. It turns an expression over observable state into an AsyncSequence:</li></ul><pre>let names = Observations { viewModel.name }<br><br>Task {<br>    for await name in names {<br>        print(&quot;Name is now \(name)&quot;)<br>    }<br>}</pre><p>Observations is designed around transactions, meaning it groups changes that happen together. Don&#39;t rely on seeing every intermediate value if a property changes several times in quick succession. If you need to support versions before iOS 26, you&#39;ll need a fallback built on withObservationTracking.</p><h3>Part 5: What doesn’t migrate cleanly</h3><h4>Sharing one source with many subscribers</h4><p>RxSwift’s share() and replay operators have no built-in equivalent. An AsyncStream is meant for a single consumer, so two tasks iterating the same stream compete for elements instead of each receiving all of them. Your options:</p><ul><li>Create a new stream per subscriber from a factory function.</li><li>Keep a list of continuations in an actor and fan each value out to all of them.</li></ul><p>If your codebase leans heavily on share(), budget extra time here.</p><h4>Backpressure and buffering</h4><p>By default an AsyncStream buffers without limit. If a fast producer feeds a slow consumer, choose a buffering policy such as .bufferingNewest(n) when you create the stream.</p><h4>Operators with no direct equivalent</h4><p>withLatestFrom, window, buffer and retry(when:) aren&#39;t in Async Algorithms&#39; list of algorithms. In practice each becomes a small for await loop with a bit of local state, for example a variable holding the latest value from the other source.</p><h4>Error handling</h4><p>AsyncStream can&#39;t fail. Use AsyncThrowingStream when an error should end the stream, and wrap the loop in do/catch. Rx&#39;s catch, which switches to a fallback stream, has to be written by hand.</p><h4>RxCocoa and UIKit</h4><p>rx.text, rx.tap, rx.items and similar bindings have no direct counterpart. Typical replacements are:</p><ul><li>UIAction closures or target-action for taps</li><li>Text field actions or delegates for text</li><li>A diffable data source for table and collection views</li><li>A Combine publisher’s .values to bridge into async/await</li></ul><h3>Swift 6 strict concurrency</h3><p>Values crossing actor boundaries must be Sendable, so expect compiler diagnostics as you move Rx closures into Task closures. Long-lived tasks that capture self should use [weak self] if they can outlive the object.</p><h4>Testing</h4><p>RxTest and TestScheduler don&#39;t carry over. You&#39;ll write async test methods, and for time-based logic you&#39;ll want an injectable clock rather than a test scheduler.</p><h4>A safe migration plan</h4><p>You don’t need a big-bang rewrite. A sequence that works well:</p><ol><li><strong>Start with one screen or feature</strong>, not the whole app.</li><li><strong>Convert the leaves first.</strong> Turn Single-returning network and storage calls into async throws functions. Most call sites get simpler right away.</li><li><strong>Bridge at the boundary.</strong> RxSwift 6.5 added await support, so you can iterate observable.values as an async sequence. Single, Completable, Driver, Signal and Infallible support it as well. That lets new async code consume old Rx code while you migrate.</li><li><strong>Migrate view models screen by screen.</strong> BehaviorRelay and Driver become @Observable properties, and DisposeBag subscriptions become .task or stored Tasks.</li><li><strong>Leave the hard operators for last.</strong> Anything built on share(), withLatestFrom or complex scheduling can stay in Rx until everything around it is gone.</li><li><strong>Remove RxSwift and RxCocoa</strong> once no imports remain.</li></ol><h4>Quick reference: Who replaces Whom</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4e2mVjAQBbjDDiRZUlyeDA.png" /><figcaption>Quick reference who replace whom</figcaption></figure><h4>Should you migrate?</h4><p>If you’re starting a new SwiftUI app targeting iOS 17 or later, you can skip RxSwift entirely. If you have a large UIKit codebase with complex reactive pipelines, a gradual, feature-by-feature migration is usually wiser than a rewrite, and some Rx-heavy corners may be fine staying where they are.</p><p>Either way, the direction is clear. State belongs in @Observable, work belongs in async/await, and lifetime belongs to tasks.</p><p><em>Code samples are starting points. Compile them against your own toolchain, since Swift and OS releases keep evolving these APIs.</em></p><h3>Wrapping up</h3><p>RxSwift taught a whole generation of iOS developers to think in streams, and that way of thinking is still worth keeping. What’s changed is the tooling. Swift now gives you first-class ways to describe state, asynchronous work and cancellation, and for most apps those tools are simpler to read, easier to debug and don’t need a third-party dependency.</p><p>You don’t have to migrate everything at once. Convert one Single into an async function. Replace one BehaviorRelay with an @Observable property. Swap one DisposeBag for a .task. Each small step makes the code a little lighter, and the Rx-heavy corners can wait until you’re ready for them.</p><p>If you’ve already migrated, or you’re stuck on a pattern that doesn’t map cleanly, such as share() or withLatestFrom, I’d like to hear how you handled it. Leave a comment, and if this guide saved you some time, a clap or a follow helps other iOS developers find it.</p><p><strong>Further reading</strong></p><ul><li>Swift Async Algorithms announcement: <a href="https://www.swift.org/blog/swift-async-algorithms/">https://www.swift.org/blog/swift-async-algorithms/</a></li><li>SE-0475, Transactional Observation of Values (Swift Forums review thread): <a href="https://forums.swift.org/t/se-0475-transactional-observation-of-values/79224">https://forums.swift.org/t/se-0475-transactional-observation-of-values/79224</a></li><li>RxSwift 6.5.0 release notes (Swift Concurrency support): <a href="https://github.com/ReactiveX/RxSwift/releases/tag/6.5.0">https://github.com/ReactiveX/RxSwift/releases/tag/6.5.0</a></li></ul><p>Thanks for reading! If this guide helped, give it a clap 👏, repost it, or share it with an iOS developer who’s still wrestling with RxSwift.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fb8e886e0f1e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[REA: AI-Powered Reverse Engineer Anything]]></title>
            <link>https://dkvekariya.medium.com/rea-ai-powered-reverse-engineer-anything-259cb42f5699?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/259cb42f5699</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[ears]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Mon, 19 Oct 2026 07:01:02 GMT</pubDate>
            <atom:updated>2026-10-19T07:01:02.015Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>How AI agents can investigate software behavior and where human judgment still matters.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ODEJ-dMxFImhjR15oaPM0w.png" /></figure><p>When developers need to understand an application without access to its<br>source code, the process can involve several specialized tools, manual<br>analysis, and a lot of context switching. <strong>REA (Reverse Engineer<br>Anything)</strong> explores a different workflow: connect an AI coding agent to<br>reverse-engineering tools, let it investigate a target, and return<br>findings with evidence that can guide further questions or<br>implementation.</p><p>Project: <a href="https://github.com/morluto/rea">github.com/morluto/rea</a></p><h3>What is REA?</h3><p>REA is an open-source toolkit that exposes reverse-engineering workflows<br>through a command-line interface (CLI) and the Model Context Protocol<br>(MCP). This lets compatible AI agents request analysis, inspect results,<br>and use those findings as context for follow-up work.</p><p>Depending on the target and configured tools, REA can help examine<br>native binaries, JavaScript and Electron applications, .NET assemblies,<br>application packages and resources, and aspects of runtime behavior.<br>Native analysis can surface items such as pseudocode, assembly, strings,<br>symbols, function calls, and references. Other workflows can map<br>JavaScript modules and imports or capture observable process behavior.</p><p>The key idea is not simply to ask an AI model to guess how an<br>application works. REA aims to give the agent access to analysis tools<br>and evidence it can use to support its conclusions.</p><h3>How the workflow works</h3><p>At a high level, the process looks like this:</p><ol><li><strong>Choose a target.</strong> Provide an application, binary, package, or<br>other supported artifact that you are authorized to inspect.</li><li><strong>Investigate with tools.</strong> The agent uses REA through MCP or the<br>CLI to request relevant analysis.</li><li><strong>Review evidence.</strong> Results can include technical details that help<br>explain how a component behaves and how different parts relate.</li><li><strong>Ask follow-up questions.</strong> The agent can use those findings to<br>narrow its investigation rather than starting from assumptions each<br>time.</li><li><strong>Implement and test.</strong> If the goal is to build a compatible<br>feature, the agent can use the findings as a starting point for an<br>implementation that still needs validation.</li></ol><p>For example, a developer might ask an agent to investigate how a search<br>feature is structured in an application, explain the evidence behind its<br>findings, and then help build a similar feature in a different codebase.</p><h3>Why developers may find it useful</h3><h4>1. A more connected investigation process</h4><p>Reverse engineering often involves moving between disassemblers,<br>decompilers, command-line utilities, and notes. REA provides a common<br>agent-facing workflow for supported tools, potentially reducing some of<br>that manual coordination.</p><h4>2. Evidence can make explanations more useful</h4><p>An AI-generated explanation is only as dependable as the information<br>behind it. REA emphasizes returning findings and evidence, giving<br>developers something concrete to inspect instead of relying solely on a<br>confident-sounding answer.</p><h4>3. It can connect investigation with implementation</h4><p>Understanding unfamiliar software and writing a new implementation are<br>usually separate activities. An agent-assisted workflow can keep<br>analysis and implementation in the same session, while allowing the<br>developer to adapt the result to their own architecture, requirements,<br>and technology stack.</p><h4>4. Local analysis can help with control</h4><p>REA describes its analysis as local. However, developers should still<br>check the data-handling policy of the AI model provider they use: tool<br>results sent to an agent may be processed under that provider’s terms.</p><h3>The trade-offs to consider</h3><p>REA is not a one-click source-code recovery tool. Decompiled pseudocode<br>and reconstructed relationships are not the same as the original source,<br>comments, design intent, or complete project history. Results may be<br>incomplete, and the agent can still misinterpret evidence.</p><p>Setup also depends on the type of target. The project currently requires<br>a compatible Node.js version and npm, while some deep native-binary<br>workflows need an additional analysis engine such as Hopper, Ghidra, or<br>IDA. Platform support and prerequisites vary by workflow, so users<br>should check the current documentation before starting.</p><p>There is also a practical validation cost. Any code created from<br>reverse-engineering findings needs review, tests, and checks for<br>behavioral differences, security issues, performance, and<br>maintainability. A plausible explanation is not proof that a recreated<br>feature is equivalent.</p><p>Finally, reverse engineering has legal, ethical, and contractual<br>boundaries. Use these tools for legitimate research, education,<br>interoperability, preservation, security work, or software you own or<br>are authorized to examine. Do not treat technical capability as<br>permission.</p><h3>Getting started</h3><p>The project’s current README documents setup and supported workflows. A common starting point is:</p><pre>npx rea-agents setup</pre><p>Review the setup changes, configure any required analysis provider, and<br>restart your compatible agent as instructed. Before analyzing a<br>particular target, check its requirements and the relevant guide in the<br>official repository.</p><ul><li><strong>Repository:</strong><br><a href="https://github.com/morluto/rea">github.com/morluto/rea</a></li><li><strong>Setup and documentation:</strong> See the project’s README and linked<br>guides for current requirements, supported agents, providers, and<br>commands.</li></ul><h3>The bigger picture</h3><p>REA reflects a broader direction in AI-assisted development: agents are<br>becoming more useful when they can call specialized tools and inspect<br>evidence, rather than working only from prompts and pasted code. Reverse<br>engineering is a demanding test of that idea because the input may be<br>incomplete, the tools are specialized, and conclusions need careful<br>verification.</p><p>The value will depend on the target, the quality of the evidence, the<br>configured tools, and the developer’s ability to evaluate the result.<br>For some investigations, REA may shorten the path from an unfamiliar<br>artifact to a useful explanation. For others, setup complexity and<br>manual verification may remain substantial.</p><p><strong>The question worth exploring is this:</strong> if an AI agent can investigate<br>an application’s behavior and show the evidence, which parts of reverse<br>engineering become faster and which decisions should still stay firmly<br>with the developer?</p><p>💬 <strong>I’d love to hear your thoughts!</strong> Have you tried using AI agents for reverse engineering or analyzing unfamiliar codebases? What benefits or challenges have you experienced?</p><p>Explore the <a href="https://github.com/morluto/rea?utm_source=chatgpt.com">REA GitHub repository</a> and share your thoughts in the comments.</p><p><strong>Would you trust an AI agent to investigate an unfamiliar application? Why or why not?</strong></p><p>If you found this article useful, consider sharing it with other developers, leaving a comment, and following for more articles on AI-assisted development, software architecture, and modern engineering tools.</p><p>Thanks again for reading. Happy coding! 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=259cb42f5699" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Functional Programming in Swift: map, filter, reduce, and Beyond]]></title>
            <link>https://dkvekariya.medium.com/functional-programming-in-swift-map-filter-reduce-and-beyond-a3ad4bb2ce26?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/a3ad4bb2ce26</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios-development]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 16 Oct 2026 14:16:01 GMT</pubDate>
            <atom:updated>2026-10-16T14:16:01.824Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Stop writing loops to transform data. Start writing transformations that compose.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pYji0shlbToCuffDNDPJgA.png" /></figure><h3>A Different Way to Think About Data</h3><p>Most developers learn to transform data with loops. Iterate, check a condition, append to a result array, return it. It works. It is also verbose, stateful, and harder to test than it needs to be.</p><p>Functional programming offers a different mental model. Instead of describing <em>how</em> to transform data step by step, you describe <em>what</em> the transformation is. The result is code that is shorter, more readable, and easier to combine into pipelines.</p><p>Swift has first-class support for this style. You have been using the pieces since <a href="https://dkvekariya.medium.com/91d441e21f24"><strong>Article 7 (closures</strong></a>). Now they come together.</p><h3>map: Transform Every Element</h3><p>map applies a transformation to every element and returns a new collection.</p><pre>let prices = [10.0, 25.0, 8.5, 42.0]<br><br>// Loop style<br>var discounted: [Double] = []<br>for price in prices {<br>    discounted.append(price * 0.9)<br>}<br><br>// Functional style<br>let discounted = prices.map { $0 * 0.9 }<br>// [9.0, 22.5, 7.65, 37.8]</pre><p>Same result. The functional version says exactly what it is: a 10% discount applied to every price. No accumulator variable, no loop management, no mutation.</p><pre>let usernames = [&quot;aryan&quot;, &quot;riya&quot;, &quot;dev&quot;]<br>let displayNames = usernames.map { $0.capitalized }<br>// [&quot;Aryan&quot;, &quot;Riya&quot;, &quot;Dev&quot;]<br><br>struct User { let id: Int; let name: String }<br>let users = [User(id: 1, name: &quot;Aryan&quot;), User(id: 2, name: &quot;Riya&quot;)]<br>let names = users.map { $0.name }<br>// [&quot;Aryan&quot;, &quot;Riya&quot;]</pre><p>map works on any Sequence and always returns an array of the same length.</p><h3>filter: Keep What Passes</h3><p>filter returns only the elements that satisfy a condition.</p><pre>let scores = [45, 78, 92, 61, 88, 34, 95]<br><br>let passing = scores.filter { $0 &gt;= 60 }<br>// [78, 92, 61, 88, 95]<br>let products = [<br>    Product(name: &quot;Swift Book&quot;, inStock: true),<br>    Product(name: &quot;Keyboard&quot;, inStock: false),<br>    Product(name: &quot;Monitor&quot;, inStock: true)<br>]<br>let available = products.filter { $0.inStock }<br>// [Swift Book, Monitor]</pre><p>The closure returns Bool. Elements that return true are kept. Elements that return false are dropped.</p><h3>reduce: Collapse to a Single Value</h3><p>reduce takes a collection and produces a single result by combining elements one at a time.</p><pre>let numbers = [1, 2, 3, 4, 5]<br>let sum = numbers.reduce(0) { result, next in result + next }<br><br>// 15<br>// Shorthand with operator function<br>let sum = numbers.reduce(0, +)<br><br>// 15<br>let words = [&quot;Swift&quot;, &quot;is&quot;, &quot;great&quot;]<br>let sentence = words.reduce(&quot;&quot;) { $0 + ($0.isEmpty ? &quot;&quot; : &quot; &quot;) + $1 }<br>// &quot;Swift is great&quot;</pre><p>The first argument is the initial value. The closure takes the accumulated result and the next element, and returns the new accumulated value.</p><pre>// Real-world: total cart price with discount<br>struct CartItem { let price: Double; let quantity: Int }<br><br>let cart = [CartItem(price: 9.99, quantity: 2), CartItem(price: 24.99, quantity: 1)]<br>let total = cart.reduce(0.0) { $0 + ($1.price * Double($1.quantity)) }<br>// 44.97</pre><h3>Chaining: Build Pipelines</h3><p>The real power comes from chaining transformations.</p><pre>let orders = [<br>    Order(amount: 120.0, isPaid: true),<br>    Order(amount: 45.0, isPaid: false),<br>    Order(amount: 300.0, isPaid: true),<br>    Order(amount: 15.0, isPaid: false),<br>    Order(amount: 89.0, isPaid: true)<br>]<br><br>let totalPaidRevenue = orders<br>    .filter { $0.isPaid }         // keep paid orders<br>    .map { $0.amount }            // extract amounts<br>    .reduce(0, +)                 // sum them<br>// 509.0</pre><p>Each step is a single, focused transformation. Read it top to bottom like a sentence. No intermediate variables, no mutation, no mental overhead tracking state.</p><h3>flatMap: Transform and Flatten</h3><p>flatMap is map followed by flattening one level of nesting.</p><pre>let sentences = [&quot;Swift is great&quot;, &quot;Generics are powerful&quot;]<br><br>let words = sentences.map { $0.split(separator: &quot; &quot;).map(String.init) }<br>// [[&quot;Swift&quot;, &quot;is&quot;, &quot;great&quot;], [&quot;Generics&quot;, &quot;are&quot;, &quot;powerful&quot;]]<br>// Nested array - probably not what you want<br>let words = sentences.flatMap { $0.split(separator: &quot; &quot;).map(String.init) }<br>// [&quot;Swift&quot;, &quot;is&quot;, &quot;great&quot;, &quot;Generics&quot;, &quot;are&quot;, &quot;powerful&quot;]<br>// Flat array - much more useful<br><br>// Flattening optional results<br>let strings = [&quot;1&quot;, &quot;two&quot;, &quot;3&quot;, &quot;four&quot;, &quot;5&quot;]<br>let numbers = strings.flatMap { Int($0) }<br>// [1, 3, 5] - nils removed, results flattened</pre><p>When the transformation returns an array, flatMap merges all the resulting arrays into one.</p><h3>compactMap: Remove Nils</h3><p>compactMap maps and removes nil results in one step.</p><pre>let inputs = [&quot;42&quot;, &quot;hello&quot;, &quot;7&quot;, &quot;world&quot;, &quot;13&quot;]<br>let numbers = inputs.compactMap { Int($0) }<br>// [42, 7, 13]<br><br>let rawIDs: [String?] = [&quot;usr_1&quot;, nil, &quot;usr_3&quot;, nil, &quot;usr_5&quot;]<br>let validIDs = rawIDs.compactMap { $0 }<br>// [&quot;usr_1&quot;, &quot;usr_3&quot;, &quot;usr_5&quot;]</pre><p>This replaces a common pattern:</p><pre>// Before<br>var result: [Int] = []<br>for str in inputs {<br>    if let n = Int(str) { result.append(n) }<br>}<br><br>// After<br>let result = inputs.compactMap { Int($0) }</pre><p>Same output. Dramatically less code. No mutation.</p><h3>zip: Combine Two Sequences</h3><p>zip pairs elements from two sequences together.</p><pre>let names = [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;]<br>let scores = [95, 87, 92]<br><br>let leaderboard = zip(names, scores).map { &quot;\($0): \($1)&quot; }<br>// [&quot;Alice: 95&quot;, &quot;Bob: 87&quot;, &quot;Charlie: 92&quot;]<br>// Sort by score descending<br>let ranked = zip(names, scores)<br>    .sorted { $0.1 &gt; $1.1 }<br>    .map { &quot;\($0.0): \($0.1)&quot; }<br>// [&quot;Alice: 95&quot;, &quot;Charlie: 92&quot;, &quot;Bob: 87&quot;]</pre><p>zip stops at the shorter sequence, so no index out of bounds risk.</p><h3>sorted and Custom Comparators</h3><pre>let users = [<br>    User(name: &quot;Riya&quot;, age: 25),<br>    User(name: &quot;Aryan&quot;, age: 28),<br>    User(name: &quot;Dev&quot;, age: 22)<br>]<br><br>// Sort by age ascending<br>let byAge = users.sorted { $0.age &lt; $1.age }<br><br>// Sort by name<br>let byName = users.sorted { $0.name &lt; $1.name }<br><br>// Sort by multiple criteria: age descending, then name ascending<br>let complex = users.sorted {<br>    if $0.age != $1.age { return $0.age &gt; $1.age }<br>    return $0.name &lt; $1.name<br>}</pre><h3>Real-World Pipeline: Processing an API Response</h3><pre>struct APIProduct: Decodable {<br>    let id: String<br>    let name: String<br>    let price: Double?<br>    let category: String<br>    let isAvailable: Bool<br>}<br><br>struct DisplayProduct {<br>    let id: String<br>    let title: String<br>    let formattedPrice: String<br>}<br>func processProducts(_ raw: [APIProduct]) -&gt; [DisplayProduct] {<br>    raw<br>        .filter { $0.isAvailable &amp;&amp; $0.price != nil }<br>        .filter { $0.category == &quot;electronics&quot; }<br>        .sorted { $0.price! &lt; $1.price! }<br>        .prefix(10)<br>        .compactMap { product -&gt; DisplayProduct? in<br>            guard let price = product.price else { return nil }<br>            return DisplayProduct(<br>                id: product.id,<br>                title: product.name.capitalized,<br>                formattedPrice: String(format: &quot;$%.2f&quot;, price)<br>            )<br>        }<br>}</pre><p>No mutation. No intermediate arrays. One clean pipeline from raw API data to display-ready models.</p><h3>Interview Questions</h3><p><strong>Q: What is the difference between map, flatMap, and compactMap in Swift?</strong></p><p>map transforms each element and returns an array of the same length. flatMap transforms each element where the transformation returns a sequence, then flattens all results into a single array. compactMap transforms each element, removes nil results, and returns an array of unwrapped values. Use map for one-to-one transformations, flatMap when each element produces multiple results, and compactMap when the transformation might fail and you want to silently drop failures.</p><p><strong>Q: Why is the functional style preferred over loops for data transformation in Swift?</strong></p><p>Functional transformations are declarative. They say what the result is rather than how to produce it step by step. This makes each step independently readable and testable. Chained transformations have no shared mutable state between steps, which eliminates a whole class of bugs. They also compose cleanly: adding a new filter or transform means adding one line to the chain rather than modifying existing loop logic.</p><h3>Summary</h3><ul><li>map transforms every element and returns an array of the same length.</li><li>filter returns only elements that satisfy a condition.</li><li>reduce collapses a collection to a single value.</li><li>Chaining filter, map, and reduce creates readable, declarative data pipelines.</li><li>flatMap maps and flattens one level of nesting in the result.</li><li>compactMap maps and removes nil results in a single step.</li><li>zip pairs elements from two sequences without risk of index out of bounds.</li><li>sorted accepts a comparator closure and supports multi-criteria sorting.</li><li>Functional transformations have no shared mutable state, making them easier to test and compose.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Given let temperatures = [36.6, 37.2, 38.1, 36.9, 39.0, 37.5], use filter to find fever temperatures (above 37.5), map to format them as strings like &quot;38.1°C&quot;, and reduce to find the average fever temperature.</li><li><strong>Intermediate:</strong> You have let logs: [String] = [&quot;ERROR: disk full&quot;, &quot;INFO: app started&quot;, &quot;ERROR: timeout&quot;, &quot;DEBUG: request sent&quot;, &quot;ERROR: auth failed&quot;]. Use compactMap to extract only the error messages (remove the &quot;ERROR: &quot; prefix), sorted to alphabetize them, and produce a single summary string using reduce.</li><li><strong>Advanced:</strong> Build a Pipeline&lt;Input, Output&gt; struct that wraps a transformation function. Add a then&lt;NewOutput&gt; method that chains another Pipeline, returning a new Pipeline&lt;Input, NewOutput&gt;. Use it to build a reusable product-processing pipeline that filters, sorts, and maps API products in a composable way. Show how individual pipeline steps can be unit tested in isolation.</li></ol><h3>What’s Next</h3><p><strong>Article 18: Swift Async/Await: Modern Concurrency Without the Callback Chaos</strong></p><p>Functional programming gives you cleaner synchronous data transformations. Async/await gives you cleaner asynchronous ones. Before async/await, every network call, file read, and background task meant nested completion handlers and manual thread management. Swift 5.5 changed that entirely. It is one of the most impactful additions to the language in years.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If data pipelines just replaced a pile of loops in your head, tap 👏 up to 50 times and do 🔁. It helps this series reach developers still writing nested for-loops to transform API responses.</strong></p><p><strong>Follow me</strong> so Article 18 lands in your feed automatically. Async/await is next and it will change how you write every network call going forward.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3ad4bb2ce26" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Generics: Write Once, Work With Any Type]]></title>
            <link>https://dkvekariya.medium.com/swift-generics-write-once-work-with-any-type-d6640afccdc9?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/d6640afccdc9</guid>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 09 Oct 2026 14:16:01 GMT</pubDate>
            <atom:updated>2026-10-09T14:16:01.722Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>The feature behind Optional, Result, Array, and every reusable component you will ever build.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gol7L4VAPgEMDbIsU-6kug.png" /></figure><h3>Why Generics Exist</h3><p>Without generics, you write the same logic multiple times for different types.</p><pre>func printInt(_ value: Int) { print(value) }<br>func printString(_ value: String) { print(value) }<br>func printDouble(_ value: Double) { print(value) }</pre><p>Three functions. Same body. Only the type differs. This does not scale. Generics solve it.</p><pre>func printValue&lt;T&gt;(_ value: T) {<br>    print(value)<br>}<br><br>printValue(42)        // works<br>printValue(&quot;hello&quot;)   // works<br>printValue(3.14)      // works</pre><p>One function. Any type. The compiler generates the right version for each call automatically.</p><h3>Generic Functions</h3><p>The &lt;T&gt; is a <strong>type parameter</strong>. It is a placeholder that Swift fills in at the call site.</p><pre>func swap&lt;T&gt;(_ a: inout T, _ b: inout T) {<br>    let temp = a<br>    a = b<br>    b = temp<br>}<br><br>var x = 10<br>var y = 20<br>swap(&amp;x, &amp;y)<br><br>print(x, y)  // 20 10<br><br>var hello = &quot;hello&quot;<br>var world = &quot;world&quot;<br>swap(&amp;hello, &amp;world)<br><br>print(hello, world)  // world hello</pre><p>T can be named anything. T and U are conventions for single and paired type parameters. Use descriptive names when the meaning matters: Element, Key, Value.</p><h3>Generic Types</h3><p><a href="https://dkvekariya.medium.com/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659"><strong>Structs</strong></a>, classes, and <a href="https://dkvekariya.medium.com/swift-enums-associated-values-raw-values-and-pattern-matching-a5844461beb1"><strong>enums</strong></a> can all be generic.</p><pre>struct Stack&lt;Element&gt; {<br>    private var storage: [Element] = []<br><br>    mutating func push(_ item: Element) {<br>        storage.append(item)<br>    }<br><br>    mutating func pop() -&gt; Element? {<br>        storage.popLast()<br>    }<br><br>    var top: Element? {<br>        storage.last<br>    }<br><br>    var isEmpty: Bool {<br>        storage.isEmpty<br>    }<br>}<br><br>var intStack = Stack&lt;Int&gt;()<br>intStack.push(1)<br>intStack.push(2)<br>intStack.push(3)<br><br>print(intStack.pop())  // Optional(3)<br><br>var stringStack = Stack&lt;String&gt;()<br>stringStack.push(&quot;Swift&quot;)<br>stringStack.push(&quot;Generics&quot;)<br><br>print(stringStack.top)  // Optional(&quot;Generics&quot;)</pre><p>One Stack implementation. Works for Int, String, User, or any type you throw at it. The type safety is fully preserved — an Stack&lt;Int&gt; cannot hold a String.</p><h3>Type Constraints</h3><p>Unconstrained generics can only use operations available on every type. To use specific capabilities, add a constraint.</p><pre>// Without constraint — T could be anything, very limited<br>func bigger&lt;T&gt;(_ a: T, _ b: T) -&gt; T {<br>    // Cannot use &gt; here — not all types support it<br>}<br><br>// With Comparable constraint - now &gt; is available<br>func bigger&lt;T: Comparable&gt;(_ a: T, _ b: T) -&gt; T {<br>    a &gt; b ? a : b<br>}<br><br>bigger(3, 7)        // 7<br>bigger(&quot;apple&quot;, &quot;mango&quot;)  // &quot;mango&quot; - String is Comparable</pre><p>Constraints can stack:</p><pre>func findAndPrint&lt;T: Comparable &amp; CustomStringConvertible&gt;(_ array: [T]) {<br>    if let max = array.max() {<br>        print(&quot;Max: \(max.description)&quot;)<br>    }<br>}</pre><p>T must be both Comparable and CustomStringConvertible. The compiler enforces this at every call site.</p><h3>Generic Constraints with where</h3><p>The where clause adds constraints inline without cluttering the function signature.</p><pre>func merge&lt;T, U&gt;(_ dict1: [T: U], _ dict2: [T: U]) -&gt; [T: U] where T: Hashable {<br>    dict1.merging(dict2) { first, _ in first }<br>}<br><br>func allEqual&lt;T: Collection&gt;(_ collection: T) -&gt; Bool where T.Element: Equatable {<br>    guard let first = collection.first else { return true }<br>    return collection.allSatisfy { $0 == first }<br>}<br><br>allEqual([1, 1, 1])       // true<br>allEqual([&quot;a&quot;, &quot;a&quot;, &quot;b&quot;]) // false</pre><p>where is particularly useful when constraining associated types of <a href="https://dkvekariya.medium.com/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>protocols</strong></a> used as parameters.</p><h3>Associated Types in Protocols</h3><p><a href="https://dkvekariya.medium.com/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>Protocols</strong></a> use associatedtype instead of &lt;T&gt; to define a generic requirement.</p><pre>protocol Container {<br>    associatedtype Item<br>    mutating func add(_ item: Item)<br>    func contains(_ item: Item) -&gt; Bool<br>    var count: Int { get }<br>}<br><br>struct Bag&lt;T: Equatable&gt;: Container {<br>    typealias Item = T<br>    private var items: [T] = []<br>    mutating func add(_ item: T) {<br>        items.append(item)<br>    }<br>    func contains(_ item: T) -&gt; Bool {<br>        items.contains(item)<br>    }<br>    var count: Int { items.count }<br>}<br><br>var bag = Bag&lt;String&gt;()<br>bag.add(&quot;Swift&quot;)<br>bag.add(&quot;Generics&quot;)<br>print(bag.contains(&quot;Swift&quot;))  // true<br>print(bag.count)              // 2</pre><p>Associated types let <a href="https://dkvekariya.medium.com/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970">protocols</a> be generic without the angle bracket syntax. This is how Collection, Sequence, and IteratorProtocol in the standard library are designed.</p><h3>Generic Extensions</h3><p>Add behavior to a generic type conditionally.</p><pre>extension Stack where Element: Equatable {<br>    func contains(_ item: Element) -&gt; Bool {<br>        storage.contains(item)<br>    }<br>}<br><br>extension Stack: CustomStringConvertible where Element: CustomStringConvertible {<br>    var description: String {<br>        &quot;[&quot; + storage.map { $0.description }.joined(separator: &quot;, &quot;) + &quot;]&quot;<br>    }<br>}</pre><p>contains only exists on stacks whose elements are Equatable. description only exists when elements have a string representation. The compiler adds exactly the right capabilities to each concrete type.</p><h3>Real-World Pattern: Generic Network Layer</h3><pre>protocol APIEndpoint {<br>    associatedtype Response: Decodable<br>    var path: String { get }<br>    var method: HTTPMethod { get }<br>}<br><br>struct UsersEndpoint: APIEndpoint {<br>    typealias Response = [User]<br>    var path: String { &quot;/users&quot; }<br>    var method: HTTPMethod { .get }<br>}<br><br>struct CreateOrderEndpoint: APIEndpoint {<br>    typealias Response = Order<br>    var path: String { &quot;/orders&quot; }<br>    var method: HTTPMethod { .post }<br>}<br><br>class APIClient {<br>    func request&lt;E: APIEndpoint&gt;(_ endpoint: E) async throws -&gt; E.Response {<br>        let url = URL(string: baseURL + endpoint.path)!<br>        let (data, _) = try await URLSession.shared.data(from: url)<br>        return try JSONDecoder().decode(E.Response.self, from: data)<br>    }<br>}<br><br>let client = APIClient()<br>let users: [User] = try await client.request(UsersEndpoint())<br>let order: Order = try await client.request(CreateOrderEndpoint())</pre><p>One request function handles every endpoint in the app. The return type is inferred automatically from the endpoint&#39;s associated type. No casting. No Any. Full type safety at every call site.</p><h3>Interview Questions</h3><p><strong>Q: What are generics in Swift and why are they important?</strong></p><p>Generics let you write functions and types that work with any type while preserving full type safety. Without generics, you either duplicate code for each type or lose type safety by using Any. Generics give you both: one implementation and compile-time guarantees. Swift&#39;s Optional, <a href="https://dkvekariya.medium.com/897fb535f805"><strong>Result</strong></a>, Array, Dictionary, and most of the standard library are built on generics. They are the foundation of reusable, type-safe code in Swift.</p><p><strong>Q: What is the difference between a generic type parameter and a protocol associated type?</strong></p><p>A generic type parameter is declared at the point of use with angle brackets: func foo&lt;T&gt;(_ value: T). The caller decides what T is. A protocol associated type is declared inside a protocol with associatedtype. The conforming type decides what the associated type is. Generic parameters are for functions and types you write directly. Associated types are for <a href="https://dkvekariya.medium.com/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970">protocols</a> that need to express relationships between types without specifying them up front.</p><h3>Summary</h3><ul><li>Generics let you write one implementation that works with any type safely.</li><li>Type parameters like &lt;T&gt; are placeholders filled in at the call site.</li><li>Constraints like &lt;T: Comparable&gt; restrict which types are allowed and unlock specific capabilities.</li><li>The where clause adds constraints without cluttering the signature.</li><li><a href="https://dkvekariya.medium.com/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659">Structs</a>, classes, <a href="https://dkvekariya.medium.com/swift-enums-associated-values-raw-values-and-pattern-matching-a5844461beb1">enums</a>, and functions can all be generic.</li><li>Protocol associated types are the protocol-side equivalent of generic type parameters.</li><li>Generic extensions with constraints add behavior only when the element type qualifies.</li><li>The entire Swift standard library and most production network layers are built on generics.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Write a generic pairs&lt;T&gt;(_ array: [T]) -&gt; [(T, T)] function that returns consecutive pairs from an array: [1,2,3,4] becomes [(1,2), (2,3), (3,4)]. Handle arrays with fewer than two elements gracefully.</li><li><strong>Intermediate:</strong> Build a generic Cache&lt;Key: Hashable, Value&gt; struct with set(_ value: Value, for key: Key), get(_ key: Key) -&gt; Value?, and remove(_ key: Key) methods. Add a maxSize: Int parameter that evicts the oldest entry when the cache is full.</li><li><strong>Advanced:</strong> Design a type-safe EventBus&lt;Event&gt; using generics and associated types. Publishers post events of a specific type. Subscribers receive only the event type they registered for. The compiler should prevent subscribing to the wrong event type entirely, with no casting at the call site. Show it working with at least two distinct event types.</li></ol><h3>What’s Next</h3><p><strong>Article 17: Functional Programming in Swift: map, filter, reduce, and Beyond</strong></p><p>Generics make your types flexible. Functional programming makes your logic composable. map, filter, reduce, flatMap, compactMap, and zip are not just collection utilities. They are a fundamentally different way of thinking about data transformation. Once they click, you will find yourself writing cleaner, shorter, and more testable code across every layer of your app.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If generics finally make sense as a design tool rather than just syntax, tap 👏 up to 50 times and do 🔁. It helps this series reach developers still copying functions to handle different types.</strong></p><p><strong>Follow me</strong> so Article 17 lands in your feed automatically. Functional programming is next and it pairs perfectly with everything you just learned.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d6640afccdc9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[ARC and Memory Management: How Swift Keeps Your App From Leaking]]></title>
            <link>https://dkvekariya.medium.com/arc-and-memory-management-how-swift-keeps-your-app-from-leaking-2e9af2ea677f?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/2e9af2ea677f</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 02 Oct 2026 14:21:01 GMT</pubDate>
            <atom:updated>2026-10-02T14:21:01.492Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Every object in your app has a lifetime. ARC manages it automatically. But automatic does not mean foolproof.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*giuYM4AzNkIAQksWuGUgmQ.png" /></figure><h3>Why Memory Management Matters in Production</h3><p>An app that leaks memory does not crash immediately. It slows down. It gets warm. It consumes more RAM with every navigation until iOS kills it in the background or the user force-quits it in frustration. Memory bugs are silent killers and they are almost always caused by the same small set of patterns.</p><p>Understanding ARC is not optional knowledge for senior iOS engineers. It is foundational.</p><h3>What ARC Does</h3><p><strong>Automatic Reference Counting</strong> tracks how many references point to each class instance. When that count reaches zero, ARC deallocates the object and reclaims the memory.</p><pre>class User {<br>    let name: String<br><br>    init(name: String) {<br>        self.name = name<br>        print(&quot;\(name) initialized&quot;)<br>    }<br>    deinit {<br>        print(&quot;\(name) deallocated&quot;)<br>    }<br>}<br><br>var ref1: User? = User(name: &quot;Aryan&quot;)  // count: 1 - &quot;Aryan initialized&quot;<br>var ref2 = ref1                         // count: 2<br>var ref3 = ref1                         // count: 3<br>ref1 = nil  // count: 2<br>ref2 = nil  // count: 1<br>ref3 = nil  // count: 0 - &quot;Aryan deallocated&quot;</pre><p>ARC runs at compile time, not runtime. It inserts retain and release calls for you. No garbage collector, no pauses, no unpredictable cleanup timing.</p><h3>Strong References: The Default</h3><p>Every regular reference is <strong>strong</strong>. It increments the reference count and keeps the object alive.</p><pre>class Team {<br>    var name: String<br>    init(name: String) { self.name = name }<br>}<br><br>let team = Team(name: &quot;iOS&quot;)  // strong reference - count: 1</pre><p>Most of the time, strong is exactly what you want. The object lives as long as someone holds a reference to it.</p><h3>Retain Cycles: When ARC Gets Stuck</h3><p>A retain cycle happens when two objects hold strong references to each other. Neither count reaches zero. Neither object ever deallocates.</p><pre>class Author {<br>    var name: String<br>    var article: Article?<br><br>    init(name: String) { self.name = name }<br>    deinit { print(&quot;\(name) deallocated&quot;) }<br>}<br><br>class Article {<br>    var title: String<br>    var author: Author?  // strong reference back to Author<br>    init(title: String) { self.title = title }<br>    deinit { print(&quot;\(title) deallocated&quot;) }<br>}<br><br>var author: Author? = Author(name: &quot;Aryan&quot;)<br>var article: Article? = Article(title: &quot;Swift ARC&quot;)<br>author?.article = article  // Author -&gt; Article (strong)<br>article?.author = author   // Article -&gt; Author (strong)<br>author = nil   // Author count: still 1 (Article holds it)<br>article = nil  // Article count: still 1 (Author holds it)<br>// deinit never called - both objects leak</pre><p>Two objects, each keeping the other alive. The external references are gone but the cycle keeps both counts above zero forever.</p><h3>Weak References: Breaking the Cycle</h3><p>A <strong>weak</strong> reference does not increment the reference count. It does not keep the object alive. If the object deallocates, the weak reference automatically becomes nil.</p><pre>class Article {<br>    var title: String<br>    weak var author: Author?  // weak — does not keep Author alive<br>    init(title: String) { self.title = title }<br>    deinit { print(&quot;\(title) deallocated&quot;) }<br>}<br><br>var author: Author? = Author(name: &quot;Aryan&quot;)<br>var article: Article? = Article(title: &quot;Swift ARC&quot;)<br>author?.article = article<br>article?.author = author<br>author = nil   // Author count: 0 - &quot;Aryan deallocated&quot;<br>article = nil  // Article count: 0 - &quot;Swift ARC deallocated&quot;</pre><p>Cycle broken. Both objects deallocate cleanly.</p><p>Weak references must be var and optional. They can become nil at any time, so the compiler requires you to treat them as Optional.</p><h3>Unowned References: The Riskier Option</h3><p>An <strong>unowned</strong> reference also does not increment the reference count. The difference: it does not become nil when the object deallocates. Accessing an unowned reference after deallocation crashes the app.</p><pre>class Customer {<br>    var name: String<br>    var card: CreditCard?<br>    init(name: String) { self.name = name }<br>    deinit { print(&quot;\(name) deallocated&quot;) }<br>}<br><br>class CreditCard {<br>    let number: String<br>    unowned let customer: Customer  // card cannot outlive the customer<br>    init(number: String, customer: Customer) {<br>        self.number = number<br>        self.customer = customer<br>    }<br>    deinit { print(&quot;Card \(number) deallocated&quot;) }<br>}<br><br>var customer: Customer? = Customer(name: &quot;Aryan&quot;)<br>customer?.card = CreditCard(number: &quot;4111&quot;, customer: customer!)<br>customer = nil<br>// &quot;Aryan deallocated&quot;<br>// &quot;Card 4111 deallocated&quot;</pre><p>Use unowned only when you are certain the referenced object will always outlive the referencing one. If there is any doubt, use weak. A crash from an invalid unowned reference is harder to diagnose than an unexpected nil.</p><h3>The Closure Retain Cycle</h3><p><a href="https://medium.com/@dkvekariya/swift-closures-the-concept-that-unlocks-everything-else-91d441e21f24"><strong>Closures</strong></a> are the most common source of retain cycles in real iOS code. A closure stored as a property captures self strongly by default. If self also holds the closure, you have a cycle.</p><pre>class VideoPlayer {<br>    var onPlaybackEnd: (() -&gt; Void)?<br><br>    func setup() {<br>        onPlaybackEnd = {<br>            self.reset()  // strong capture of self<br>        }<br>        // VideoPlayer holds onPlaybackEnd<br>        // onPlaybackEnd holds VideoPlayer<br>        // cycle<br>    }<br><br>    func reset() { }<br>    deinit { print(&quot;VideoPlayer deallocated&quot;) }<br>}</pre><p>Fix with a capture list:</p><pre>onPlaybackEnd = { [weak self] in<br>    self?.reset()<br>}</pre><p>This is the pattern from <a href="https://medium.com/@dkvekariya/swift-closures-the-concept-that-unlocks-everything-else-91d441e21f24"><strong>Article 7 (Closures)</strong></a> viewed through the lens of ARC. The capture list makes the closure’s reference to self weak. The cycle breaks. self deallocates when its external references are gone.</p><h3>Finding Leaks with Instruments</h3><p>Xcode’s Memory Graph Debugger is your first tool for finding retain cycles:</p><ol><li>Run your app in Xcode</li><li>Navigate to the screen you suspect is leaking</li><li>Navigate away</li><li>Click the Memory Graph button in the Debug bar</li><li>Look for objects that should have deallocated but still appear in the graph</li></ol><p>Instruments’ Leaks and Allocations templates go deeper for production profiling. Any object shown in the memory graph after it should have been released is a candidate for investigation.</p><h3>Real-World Patterns That Leak (and Their Fixes)</h3><p><strong>Timer retain cycle:</strong></p><pre>// Leak — Timer holds a strong reference to self<br>class ClockView {<br>    var timer: Timer?<br><br>    func start() {<br>        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in<br>            self.updateDisplay()  // strong capture<br>        }<br>    }<br>}<br><br>// Fix<br>timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in<br>    self?.updateDisplay()<br>}</pre><p><strong>Delegate retain cycle:</strong></p><pre>// Leak — strong delegate creates a cycle<br>class DataLoader {<br>    var delegate: DataLoaderDelegate?  // strong<br>}<br><br>// Fix - delegates are almost always weak<br>class DataLoader {<br>    weak var delegate: DataLoaderDelegate?<br>}</pre><p><strong>NotificationCenter observer not removed:</strong></p><pre>// Leak in older APIs — observer not removed<br>class ViewController: UIViewController {<br>    override func viewDidLoad() {<br>        NotificationCenter.default.addObserver(<br>            self,<br>            selector: #selector(handleUpdate),<br>            name: .dataUpdated,<br>            object: nil<br>        )<br>    }<br>    // Fix: remove in deinit or use the block-based API with [weak self]<br>    deinit {<br>        NotificationCenter.default.removeObserver(self)<br>    }<br>}</pre><h3>Interview Questions</h3><p><strong>Q: What is a retain cycle and how do you fix one in Swift?</strong></p><p>A retain cycle occurs when two or more objects hold strong references to each other, preventing ARC from ever reducing either object’s reference count to zero. Both objects leak. The fix is to break the cycle by making one reference weak or unowned. Use weak when the referenced object can outlive the referencing one and may become nil. Use unowned only when you can guarantee the referenced object always outlives the referencing one.</p><p><strong>Q: What is the difference between weak and unowned in Swift?</strong></p><p>Both are non-retaining references that do not increment ARC’s reference count. weak is always optional and automatically becomes nil when the referenced object deallocates. unowned is non-optional and does not become nil. Accessing an unowned reference after the object deallocates causes a crash. Use weak when the referenced object might deallocate before the referencing one. Use unowned when you can guarantee it will not.</p><h3>Summary</h3><ul><li>ARC automatically tracks reference counts for class instances and deallocates them at zero.</li><li>Strong references are the default and keep objects alive.</li><li>Retain cycles occur when objects hold strong references to each other, preventing deallocation.</li><li>weak references do not retain, are always optional, and become nil on deallocation.</li><li>unowned references do not retain and are non-optional. Accessing them after deallocation crashes.</li><li>Closures capture self strongly by default. Use [weak self] capture lists to break cycles.</li><li>Delegates should almost always be weak.</li><li>Timers, notification observers, and stored closures are the most common real-world leak sources.</li><li>Use Xcode’s Memory Graph Debugger and Instruments to detect leaks before they reach production.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Create two <a href="https://medium.com/@dkvekariya/swift-classes-reference-types-inheritance-and-when-to-use-them-f7a1fd4bd47c"><strong>classes</strong></a>, Parent and Child, where Parent has a strong reference to Child and Child has a strong reference back to Parent. Add deinit to both and verify they never print. Then fix the cycle using weak and verify both deinit calls fire.</li><li><strong>Intermediate:</strong> Build a EventBus class that stores an array of closures as subscribers. Show how a subscriber that captures self strongly creates a leak when the subscribing object deallocates. Fix it using [weak self] and clean up nil subscribers from the array automatically.</li><li><strong>Advanced:</strong> Profile a UIViewController subclass in Instruments that has a retain cycle caused by a Timer and a stored closure. Document exactly which reference is causing the cycle, fix it, and verify the deallocation in the Memory Graph Debugger. Write a brief post-mortem explaining the root cause, the fix, and the general rule it illustrates.</li></ol><h3>What’s Next</h3><p><strong>Article 16: Swift Generics: Write Once, Use Everywhere</strong></p><p>ARC taught you how Swift manages the lifetime of objects in memory. Generics teach you how to write code that works across types without duplicating logic. They are the foundation of Swift’s collections, Result, Optional, and almost every reusable component you will ever build.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If ARC finally clicked and you can see where your app might be leaking, tap 👏 up to 50 times. It helps this series reach developers shipping apps with silent memory bugs.</strong></p><p><strong>Follow me</strong> so Article 16 lands in your feed automatically. Generics are next and they will change how you write reusable code forever.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2e9af2ea677f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Error Handling: throw, try, catch, and Result]]></title>
            <link>https://dkvekariya.medium.com/swift-error-handling-throw-try-catch-and-result-897fb535f805?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/897fb535f805</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 25 Sep 2026 14:11:01 GMT</pubDate>
            <atom:updated>2026-09-25T14:11:01.534Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Swift forces you to acknowledge every failure path before your code builds. That is not a restriction. It is a feature.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LGNGFcp3UomCKCcKVQTpCw.png" /></figure><h3>Why Error Handling Is Not Optional</h3><p>Every app fails sometimes. Networks go down. Files go missing. Users enter bad data. JSON arrives malformed. The question is never whether your app will encounter errors. It is whether your code handles them deliberately or discovers them as crashes.</p><p>Swift’s error system makes deliberate handling the only option. If a function can throw, the compiler forces you to acknowledge that before your code builds. You cannot forget. You cannot ignore it. That guarantee is worth more than it might seem.</p><h3>Defining Errors</h3><p>Swift errors conform to the Error <a href="https://medium.com/@dkvekariya/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>protocol</strong></a>. Enums are the natural fit because they enumerate exactly what can go wrong.</p><pre>enum NetworkError: Error {<br>    case invalidURL<br>    case noConnection<br>    case timeout(after: TimeInterval)<br>    case serverError(statusCode: Int)<br>    case decodingFailed(reason: String)<br>}</pre><p>Each case is a distinct, named failure. No integer error codes. No string comparisons. The compiler knows every possible error at compile time.</p><h3>Throwing Functions</h3><p>Mark a function with throws to indicate it can fail.</p><pre>func fetchUser(id: String) throws -&gt; User {<br>    guard !id.isEmpty else {<br>        throw NetworkError.invalidURL<br>    }<br>    <br>    // Simulate fetch<br>    guard let user = database[id] else {<br>        throw NetworkError.serverError(statusCode: 404)<br>    }<br>    return user<br>}</pre><p>The throws keyword is part of the function signature. Any caller can see at a glance that this function might fail.</p><h3>Calling Throwing Functions</h3><p>You must use try when calling a throwing function. Then handle the error with do/catch.</p><pre>do {<br>    let user = try fetchUser(id: &quot;usr_001&quot;)<br>    print(&quot;Found: \(user.name)&quot;)<br>} catch NetworkError.invalidURL {<br>    print(&quot;The URL was invalid&quot;)<br>} catch NetworkError.serverError(let code) {<br>    print(&quot;Server returned \(code)&quot;)<br>} catch NetworkError.timeout(let seconds) {<br>    print(&quot;Request timed out after \(seconds)s&quot;)<br>} catch {<br>    // Catches everything else<br>    print(&quot;Unexpected error: \(error)&quot;)<br>}</pre><p>Swift’s catch supports full pattern matching, including associated values. The final bare catch is your safety net for anything you did not explicitly anticipate.</p><h3>try? and try!</h3><p>Two shorthand options when you need less ceremony.</p><pre>// try? — converts the result to Optional, nil on failure<br>let user = try? fetchUser(id: &quot;usr_001&quot;)<br>// user is User? — nil if fetchUser threw anything<br><br>// try! - force unwraps the result, crashes if it throws<br>let user = try! fetchUser(id: &quot;usr_001&quot;)<br>// Crashes at runtime if fetchUser throws</pre><p>try? is useful when failure is acceptable and you just want a nil. Loading a cached image, for example. If the cache misses, nil is fine.</p><p>try! is the same risk as force-unwrapping an <a href="https://medium.com/@dkvekariya/swift-optionals-nil-unwrapping-and-the-safety-system-behind-the-24d48687694f"><strong>optional</strong></a>. Use it only when you are certain the function cannot throw in this context, and document why.</p><h3>Propagating Errors</h3><p>Throwing functions can propagate errors up the call stack instead of handling them immediately. Mark the caller as throws too.</p><pre>func loadUserProfile(id: String) throws -&gt; UserProfile {<br>    let user = try fetchUser(id: id)       // propagates if this throws<br>    let posts = try fetchPosts(for: user)  // propagates if this throws<br>    return UserProfile(user: user, posts: posts)<br>}</pre><p>The error bubbles up until something catches it. This lets you handle errors at the right layer instead of wrapping every function call in do/catch.</p><h3>Result&lt;Success, Failure&gt;: Errors as Values</h3><p>Result is Swift&#39;s enum for representing success or failure as a value rather than through throwing.</p><pre>enum Result&lt;Success, Failure: Error&gt; {<br>    case success(Success)<br>    case failure(Failure)<br>}</pre><p>Use it when you need to store an error, pass it to a completion handler, or work with APIs that use callbacks instead of async/await.</p><pre>func fetchUser(id: String, completion: @escaping (Result&lt;User, NetworkError&gt;) -&gt; Void) {<br>    guard !id.isEmpty else {<br>        completion(.failure(.invalidURL))<br>        return<br>    }<br><br>    // Simulate async fetch<br>    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {<br>        if let user = self.database[id] {<br>            completion(.success(user))<br>        } else {<br>            completion(.failure(.serverError(statusCode: 404)))<br>        }<br>    }<br>}<br><br>// Call site<br>fetchUser(id: &quot;usr_001&quot;) { result in<br>    switch result {<br>    case .success(let user):<br>        print(&quot;Loaded: \(user.name)&quot;)<br>    case .failure(let error):<br>        print(&quot;Failed: \(error)&quot;)<br>    }<br>}</pre><p>Result makes the success and failure paths explicit and equal. No hidden <a href="https://medium.com/@dkvekariya/swift-optionals-nil-unwrapping-and-the-safety-system-behind-the-24d48687694f"><strong>optional</strong></a>, no separate error parameter.</p><h3>Converting Between throws and Result</h3><p>Swift makes this seamless.</p><pre>// throws -&gt; Result<br>let result = Result { try fetchUser(id: &quot;usr_001&quot;) }<br><br>// Result -&gt; throws<br>let user = try result.get()</pre><p>Result { } captures any thrown error into .failure. .get() throws the failure back out. Use whichever style fits the surrounding code.</p><h3>rethrows: Conditional Throwing</h3><p>A function marked rethrows only throws if one of its closure parameters throws.</p><pre>func transform&lt;T&gt;(_ values: [T], using block: (T) throws -&gt; T) rethrows -&gt; [T] {<br>    try values.map(block)<br>}<br><br>// Non-throwing closure - transform doesn&#39;t throw<br>let doubled = transform([1, 2, 3]) { $0 * 2 }<br>// Throwing closure - transform can throw<br>let parsed = try transform([&quot;1&quot;, &quot;two&quot;, &quot;3&quot;]) { str in<br>    guard let int = Int(str) else { throw ParseError.invalid(str) }<br>    return int<br>}</pre><p>rethrows is how map, filter, and forEach in the standard library work. They only require try when the closure you pass them throws.</p><h3>Real-World Pattern: Layered Error Handling</h3><p>Production apps translate low-level errors into user-facing messages at the right layer.</p><pre>enum AppError: Error, LocalizedError {<br>    case networkUnavailable<br>    case sessionExpired<br>    case contentNotFound<br>    case unknown(Error)<br><br>    var errorDescription: String? {<br>        switch self {<br>        case .networkUnavailable:  return &quot;Check your internet connection and try again.&quot;<br>        case .sessionExpired:      return &quot;Your session has expired. Please log in again.&quot;<br>        case .contentNotFound:     return &quot;This content is no longer available.&quot;<br>        case .unknown:             return &quot;Something went wrong. Please try again.&quot;<br>        }<br>    }<br>}<br><br>func mapToAppError(_ error: Error) -&gt; AppError {<br>    guard let networkError = error as? NetworkError else {<br>        return .unknown(error)<br>    }<br>    switch networkError {<br>    case .noConnection:            return .networkUnavailable<br>    case .serverError(401):        return .sessionExpired<br>    case .serverError(404):        return .contentNotFound<br>    default:                       return .unknown(error)<br>    }<br>}</pre><p>Low-level network errors stay in the networking layer. The app layer speaks in user-friendly terms. The view just reads errorDescription and displays it. Each layer handles what it knows about.</p><h3>Interview Questions</h3><p><strong>Q: What is the difference between </strong><strong>throws and </strong><strong>Result in Swift error handling?</strong></p><p>throws uses Swift&#39;s built-in error propagation mechanism. The compiler forces callers to use try and either handle or propagate the error. Result represents success or failure as a value in an enum. Use throws for synchronous code and async/await-based APIs where the compiler can enforce error handling directly. Use Result for completion handler-based APIs, when you need to store or pass an error as a value, or when working with older callback-based code.</p><p><strong>Q: What does </strong><strong>rethrows mean in Swift?</strong></p><p>rethrows marks a function that only throws if one of the closure parameters it receives throws. If you pass a non-throwing closure, the function itself does not throw and no try is needed at the call site. If you pass a throwing closure, the function can rethrow that error. This is how standard library functions like map and filter work cleanly with both throwing and non-throwing closures.</p><h3>Summary</h3><ul><li>Swift errors conform to Error. <a href="https://medium.com/@dkvekariya/swift-enums-associated-values-raw-values-and-pattern-matching-a5844461beb1"><strong>Enums with associated values</strong></a> are the cleanest modeling tool.</li><li>throws in a function signature tells every caller: this can fail.</li><li>do/catch handles errors with full pattern matching, including associated values.</li><li>try? converts failure to nil. try! crashes on failure. Use both sparingly.</li><li>Errors propagate up the call stack until something catches them.</li><li>Result&lt;Success, Failure&gt; represents success or failure as a value, ideal for completion handlers.</li><li>Result { try... } captures thrown errors. .get() throws them back out.</li><li>rethrows only propagates errors when a closure parameter itself throws.</li><li>Translate low-level errors into user-facing messages at the appropriate architectural layer.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Create a divide(_ a: Double, by b: Double) throws -&gt; Double function that throws a MathError.divisionByZero case when b is zero. Call it with do/catch, with try?, and with try!. Explain when each is appropriate.</li><li><strong>Intermediate:</strong> Build a JSONLoader struct with a load&lt;T: Decodable&gt;(_ filename: String) throws -&gt; T method that reads a JSON file from the app bundle and decodes it. Define a FileError enum covering file not found, read failure, and decoding failure with associated error messages. Chain the error propagation correctly so callers see meaningful errors.</li><li><strong>Advanced:</strong> Create a Validator&lt;T&gt; struct that takes an array of (T) throws -&gt; Void validation rules. Add a validate(_ value: T) -&gt; Result&lt;T, ValidationError&gt; method where ValidationError collects all failures, not just the first one. Use rethrows where appropriate and write a concrete example validating a RegistrationForm struct with rules for username length, email format, and password strength.</li></ol><h3>What’s Next</h3><p><strong>Article 15: ARC and Memory Management: How Swift Keeps Your App From Leaking</strong></p><p>You now know how Swift handles errors at the language level. Next: how it handles memory. Automatic Reference Counting is what keeps your objects alive exactly as long as they need to be and no longer. Understanding ARC, strong references, weak references, and retain cycles is what separates developers who write leak-free apps from those who find memory problems in production.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If Swift’s error system just made your failure handling more intentional, tap 👏 up to 50 times and do 🔁. It helps this series reach developers still using </strong><a href="https://medium.com/@dkvekariya/swift-optionals-nil-unwrapping-and-the-safety-system-behind-the-24d48687694f"><strong>optional</strong></a><strong> returns where errors belong.</strong></p><p><strong>Follow me</strong> so Article 15 lands in your feed automatically. Memory management is next and it is one of the most important topics for shipping stable iOS apps.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=897fb535f805" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Extensions: Add Behavior to Any Type Without Subclassing]]></title>
            <link>https://dkvekariya.medium.com/swift-extensions-add-behavior-to-any-type-without-subclassing-de5090ae3808?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/de5090ae3808</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 18 Sep 2026 14:11:01 GMT</pubDate>
            <atom:updated>2026-09-18T14:11:01.372Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>You can extend String, Int, UIView, or your own types. No subclass needed. No source access required.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lB7hiIeeSxK9O0L7WXPrwQ.png" /></figure><h3>Why Extensions Are One of Swift’s Best Features</h3><p>Most languages let you add behavior to a type by subclassing it or modifying it directly. Swift offers a third path: extend any type, anywhere, without touching the original source.</p><p>You can add methods to String. <a href="https://medium.com/@dkvekariya/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659">Computed properties</a> to Int. <a href="https://medium.com/@dkvekariya/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>Protocol conformances</strong></a> to types from third-party libraries. Namespace your own code into focused, readable chunks. Extensions make all of this clean and compiler-safe.</p><h3>The Basics</h3><pre>extension String {<br>    func trimmed() -&gt; String {<br>        trimmingCharacters(in: .whitespacesAndNewlines)<br>    }<br>    <br>    var isBlank: Bool {<br>        trimmed().isEmpty<br>    }<br>}<br><br>let input = &quot;  hello  &quot;<br>print(input.trimmed())  // &quot;hello&quot;<br>print(input.isBlank)    // false<br>print(&quot;   &quot;.isBlank)    // true</pre><p>Every String in your entire project now has trimmed() and isBlank. No subclass, no wrapper type, no helper function hidden in a utility file.</p><h3>What You Can Add in an Extension</h3><p>Extensions support a wide range of additions:</p><pre>extension SomeType {<br>    // Computed properties (stored properties are not allowed)<br>    var computedValue: Int { ... }<br><br>    // Methods<br>    func doSomething() { ... }<br>    // Initializers (convenience, not designated for classes)<br>    init(someParam: String) { ... }<br>    // Subscripts<br>    subscript(key: String) -&gt; String? { ... }<br>    // Nested types<br>    enum State { case active, inactive }<br>}</pre><p>One important limit: extensions cannot add <strong>stored properties</strong>. You can add <a href="https://medium.com/@dkvekariya/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659">computed properties</a> that derive their value, but you cannot add new memory to an existing type from outside its definition.</p><h3>Extending Your Own Types for Organization</h3><p>Extensions are not just for adding new behavior to foreign types. They are one of the cleanest ways to organize your own code.</p><pre>struct UserViewModel {<br>    let user: User<br>    var isLoading: Bool<br>    var errorMessage: String?<br>}<br><br>// Core data<br>extension UserViewModel {<br>    var displayName: String {<br>        user.name.isEmpty ? &quot;Anonymous&quot; : user.name<br>    }<br>    var avatarInitials: String {<br>        String(user.name.prefix(2)).uppercased()<br>    }<br>}<br>// Actions<br>extension UserViewModel {<br>    mutating func refresh() {<br>        isLoading = true<br>        errorMessage = nil<br>    }<br>    mutating func handleError(_ error: Error) {<br>        isLoading = false<br>        errorMessage = error.localizedDescription<br>    }<br>}</pre><p>Split by responsibility, not by arbitrary line count. Each extension block has one clear purpose. New team members find what they need faster.</p><h3>Protocol Conformance in Separate Extensions</h3><p>This is the pattern you will see in every serious Swift codebase.</p><pre>struct Product {<br>    let id: String<br>    let name: String<br>    let price: Double<br>}<br><br>// Core type stays clean<br>// Conformances are declared separately<br>extension Product: Equatable {<br>    static func == (lhs: Product, rhs: Product) -&gt; Bool {<br>        lhs.id == rhs.id<br>    }<br>}<br><br>extension Product: Comparable {<br>    static func &lt; (lhs: Product, rhs: Product) -&gt; Bool {<br>        lhs.price &lt; rhs.price<br>    }<br>}<br><br>extension Product: CustomStringConvertible {<br>    var description: String {<br>        &quot;\(name) - $\(String(format: &quot;%.2f&quot;, price))&quot;<br>    }<br>}</pre><p>Each conformance lives in its own extension block. When you search for “Equatable” in your file, you find it immediately. When you delete a conformance, you delete one focused block, not lines scattered through the original type.</p><h3>Extending Apple’s Types</h3><p>This is where extensions genuinely change how you write daily code.</p><pre>extension Int {<br>    var isEven: Bool { self % 2 == 0 }<br>    var isOdd: Bool { !isEven }<br>    <br>    func times(_ action: () -&gt; Void) {<br>        for _ in 0..&lt;self { action() }<br>    }<br>}<br><br>5.times { print(&quot;hello&quot;) }  // prints &quot;hello&quot; 5 times<br>print(4.isEven)              // true<br><br>extension Double {<br>    var asPercentage: String {<br>        String(format: &quot;%.1f%%&quot;, self * 100)<br>    }<br>}<br><br>print(0.856.asPercentage)  // &quot;85.6%&quot;<br><br>extension Array {<br>    func chunked(into size: Int) -&gt; [[Element]] {<br>        stride(from: 0, to: count, by: size).map {<br>            Array(self[$0..&lt;Swift.min($0 + size, count)])<br>        }<br>    }<br>}<br><br>let pages = [1,2,3,4,5,6,7].chunked(into: 3)<br>// [[1,2,3], [4,5,6], [7]]<br><br>extension Optional where Wrapped == String {<br>    var orEmpty: String {<br>        self ?? &quot;&quot;<br>    }<br>}<br><br>let name: String? = nil<br>print(name.orEmpty)  // &quot;&quot;</pre><p>These are not clever tricks. They are the kind of extensions that end up in every production iOS codebase because they eliminate repetitive unwrapping and formatting code across hundreds of files.</p><h3>Extensions with Constraints</h3><p>You can limit an extension to only apply when generic type parameters meet a condition.</p><pre>extension Array where Element: Numeric {<br>    var sum: Element {<br>        reduce(0, +)<br>    }<br>    <br>    var average: Double {<br>        guard !isEmpty else { return 0 }<br>        return Double(sum as! Double) / Double(count)<br>    }<br>}<br><br>[1, 2, 3, 4, 5].sum  // 15</pre><p>Or for your own generic types:</p><pre>extension Stack where T: Equatable {<br>    func contains(_ value: T) -&gt; Bool {<br>        storage.contains(value)<br>    }<br>}</pre><p>The contains method only exists when the stack holds Equatable elements. The compiler enforces this. You don&#39;t need runtime checks.</p><h3>What Extensions Cannot Do</h3><p>A few limits worth knowing upfront:</p><pre>extension String {<br>    // ❌ Cannot add stored properties<br>    var someStoredValue: Int = 0<br><br>    // ❌ Cannot override existing methods (use subclassing for that)<br>    // override func hasPrefix(_ prefix: String) -&gt; Bool { ... }<br>}</pre><p>Extensions also cannot add designated initializers to classes or add deinit. These rules keep extensions predictable: they add to a type, they don&#39;t restructure it.</p><h3>Real-World Pattern: UIColor Extension</h3><pre>extension UIColor {<br>    convenience init(hex: String) {<br>        var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)<br>        hexSanitized = hexSanitized.replacingOccurrences(of: &quot;#&quot;, with: &quot;&quot;)<br>      <br>        var rgb: UInt64 = 0<br>        Scanner(string: hexSanitized).scanHexInt64(&amp;rgb)<br>        let r = CGFloat((rgb &amp; 0xFF0000) &gt;&gt; 16) / 255<br>        let g = CGFloat((rgb &amp; 0x00FF00) &gt;&gt; 8) / 255<br>        let b = CGFloat(rgb &amp; 0x0000FF) / 255<br>        self.init(red: r, green: g, blue: b, alpha: 1)<br>    }<br><br>    static let brandPrimary = UIColor(hex: &quot;#4A90E2&quot;)<br>    static let brandSecondary = UIColor(hex: &quot;#F5A623&quot;)<br>}<br><br>// Usage<br>view.backgroundColor = .brandPrimary<br>label.textColor = UIColor(hex: &quot;#333333&quot;)</pre><p>This is a convenience initializer added to UIColor from Apple&#39;s UIKit. You cannot modify UIKit&#39;s source. Extensions make this possible cleanly.</p><h3>Interview Questions</h3><p><strong>Q: What can and cannot be added to a type via an extension in Swift?</strong></p><p>Extensions can add <a href="https://medium.com/@dkvekariya/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659"><strong>computed properties</strong></a>, methods, initializers (convenience initializers for classes), subscripts, nested types, and <a href="https://medium.com/@dkvekariya/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>protocol conformances</strong></a>. They cannot add stored properties, cannot override existing implementations (that requires subclassing), and cannot add designated initializers or deinit to classes. The constraint on stored properties exists because extensions cannot change the memory layout of a type defined elsewhere.</p><p><strong>Q: Why do senior Swift engineers put protocol conformances in separate extension blocks?</strong></p><p>Separating conformances into distinct extensions makes each one easy to find, reason about, and delete independently. When you search for Equatable conformance, you find one focused block rather than code scattered through the main type definition. It also makes code review cleaner: a diff that adds Codable conformance via an extension is immediately understandable without reading the entire type.</p><h3>Summary</h3><ul><li>Extensions add <a href="https://medium.com/@dkvekariya/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659"><strong>computed properties</strong></a>, methods, initializers, subscripts, and <a href="https://medium.com/@dkvekariya/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>protocol conformances</strong></a> to any type.</li><li>Extensions cannot add stored properties or override existing methods.</li><li>Organizing your own types into focused extension blocks by responsibility improves readability and navigation.</li><li><a href="https://medium.com/@dkvekariya/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970"><strong>Protocol conformances</strong></a> in separate extension blocks make each conformance easy to find and remove.</li><li>Constrained extensions apply only when generic parameters meet specific requirements.</li><li>Extensions on Apple’s types like String, Array, and UIColor eliminate repetitive utility code across a codebase.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Write extensions on String for isValidEmail: Bool (basic format check), wordCount: Int, and capitalizingFirstLetter() -&gt; String. Use them in a form validation function.</li><li><strong>Intermediate:</strong> Extend Array with three useful methods: second: Element? (returns the second element safely), groupedBy&lt;Key: Hashable&gt;(_ keyPath: KeyPath&lt;Element, Key&gt;) -&gt; [Key: [Element]], and removingDuplicates() -&gt; [Element] where Element: Equatable. Write tests for each.</li><li><strong>Advanced:</strong> Create a UserDefaults extension that uses a generic subscript with Codable constraints to read and write any Codable type. Use @propertyWrapper style with a custom Persisted&lt;T: Codable&gt; wrapper that reads from and writes to UserDefaults automatically. Show how it eliminates boilerplate compared to raw UserDefaults usage.</li></ol><h3>What’s Next</h3><p><strong>Article 14: Swift Error Handling: throw, try, catch, and Result</strong></p><p>Extensions make your types richer. Error handling makes them honest. Swift’s error system is not just try/catch ported from other languages. It is a compile-enforced mechanism that forces you to acknowledge every failure path before your code builds. Combined with Result&lt;T, Error&gt;, it becomes one of the cleanest error propagation systems in any modern language.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If extensions changed how you think about organizing code, tap 👏 up to 50 times. It helps this series reach developers still writing utility helper files full of free functions.</strong></p><p><strong>Follow me</strong> so Article 14 lands in your feed the moment it goes live. Error handling is next and it is far more powerful than most developers realize.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=de5090ae3808" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Swift Protocols: Contracts, Conformance, and Protocol-Oriented Programming]]></title>
            <link>https://dkvekariya.medium.com/swift-protocols-contracts-conformance-and-protocol-oriented-programming-6b9d48617970?source=rss-6317b0b805bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/6b9d48617970</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Divyesh Vekariya]]></dc:creator>
            <pubDate>Fri, 11 Sep 2026 07:31:02 GMT</pubDate>
            <atom:updated>2026-09-11T07:31:02.117Z</atom:updated>
            <content:encoded><![CDATA[<h4><em>Classes give you inheritance. Protocols give you composition. One scales. One doesn’t.</em></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X8Wem04aXAO06WPI-KGPvg.png" /></figure><h3>Why Protocols Change Everything</h3><p>Swift is not an object-oriented language at heart. It is a protocol-oriented one. Apple said this at WWDC 2015 and then proceeded to build SwiftUI, Combine, and the entire standard library around it.</p><p>Understanding protocols is the difference between writing code that works and writing code that scales, composes, and stays testable as your app grows.</p><h3>What Is a Protocol?</h3><p>A protocol defines a contract. It says: “Any type that conforms to me must provide these properties and methods.” It says nothing about how they’re implemented.</p><pre>protocol Greetable {<br>    var name: String { get }<br>    func greet() -&gt; String<br>}</pre><p>Any struct, class, or enum can conform:</p><pre>struct User: Greetable {<br>    var name: String<br><br>    func greet() -&gt; String {<br>        &quot;Hello, I&#39;m \(name)&quot;<br>    }<br>}<br><br>struct Bot: Greetable {<br>    var name: String<br>    func greet() -&gt; String {<br>        &quot;BEEP. I AM \(name.uppercased()). BOOP.&quot;<br>    }<br>}</pre><p>Both types are Greetable. Both implement greet() differently. Code that accepts a Greetable works with either, without knowing which one it has.</p><h3>Protocol Properties</h3><p>Protocols specify whether a property must be gettable, settable, or both.</p><pre>protocol Vehicle {<br>    var speed: Double { get }        // read-only minimum requirement<br>    var fuelLevel: Double { get set } // must be read-write<br>    var description: String { get }<br>}</pre><p>A conforming type can satisfy { get } with either a stored property or a computed one. It must satisfy { get set } with a mutable stored property.</p><pre>struct Car: Vehicle {<br>    var speed: Double          // stored — satisfies { get }<br>    var fuelLevel: Double      // stored — satisfies { get set }<br><br>    var description: String {  // computed - also satisfies { get }<br>        &quot;Car going \(speed) km/h&quot;<br>    }<br>}</pre><h3>Default Implementations with Extensions</h3><p>Protocol extensions let you provide default behavior. Conforming types get it for free and can override it if needed.</p><pre>protocol Describable {<br>    var name: String { get }<br>    func describe() -&gt; String<br>}<br><br>extension Describable {<br>    func describe() -&gt; String {<br>        &quot;I am \(name)&quot;  // default implementation<br>    }<br>}<br>struct Product: Describable {<br>    var name: String<br>    // describe() is provided automatically<br>}<br>struct SpecialProduct: Describable {<br>    var name: String<br>    func describe() -&gt; String {<br>        &quot;Special: \(name)&quot;  // overrides the default<br>    }<br>}<br>print(Product(name: &quot;Laptop&quot;).describe())         // I am Laptop<br>print(SpecialProduct(name: &quot;Laptop&quot;).describe())  // Special: Laptop</pre><p>This is one of the most powerful patterns in Swift. Add behavior to a protocol once and every conforming type benefits. No inheritance required.</p><h3>Protocol Composition</h3><p>A type can conform to multiple protocols. You can also require multiple protocols at once using &amp;.</p><pre>protocol Flyable {<br>    func fly()<br>}<br><br>protocol Swimmable {<br>    func swim()<br>}<br>struct Duck: Flyable, Swimmable {<br>    func fly() { print(&quot;Flap flap&quot;) }<br>    func swim() { print(&quot;Splash splash&quot;) }<br>}<br>func demonstrate(_ animal: Flyable &amp; Swimmable) {<br>    animal.fly()<br>    animal.swim()<br>}<br>demonstrate(Duck())</pre><p>This is composition over inheritance. Instead of building a class hierarchy to represent a flying, swimming animal, you compose behaviors from focused protocols. Adding a Walkable protocol later doesn&#39;t require restructuring anything.</p><h3>Using Protocols as Types</h3><p>Protocols are first-class types. You can use them as parameter types, return types, and stored properties.</p><pre>protocol Shape {<br>    var area: Double { get }<br>}<br><br>struct Circle: Shape {<br>    var radius: Double<br>    var area: Double { .pi * radius * radius }<br>}<br>struct Rectangle: Shape {<br>    var width: Double<br>    var height: Double<br>    var area: Double { width * height }<br>}<br>func totalArea(of shapes: [Shape]) -&gt; Double {<br>    shapes.reduce(0) { $0 + $1.area }<br>}<br>let shapes: [Shape] = [Circle(radius: 5), Rectangle(width: 4, height: 6)]<br>print(totalArea(of: shapes))  // 102.53...</pre><p>The function doesn’t know or care whether each shape is a Circle or Rectangle. It just knows they&#39;re Shape. This is <strong>polymorphism without inheritance</strong>.</p><h3>Equatable, Comparable, Hashable: The Standard Protocols</h3><p>Swift’s standard library is built on protocols. Three you’ll use constantly:</p><pre>struct User: Equatable, Comparable, Hashable {<br>    let id: String<br>    var name: String<br><br>// Equatable - compiler synthesizes == for you if all properties are Equatable<br>    // Hashable - compiler synthesizes hash(into:) for you<br>    // Comparable - you provide this one<br>    static func &lt; (lhs: User, rhs: User) -&gt; Bool {<br>        lhs.name &lt; rhs.name<br>    }<br>}<br>let users = [User(id: &quot;2&quot;, name: &quot;Riya&quot;), User(id: &quot;1&quot;, name: &quot;Aryan&quot;)]<br>let sorted = users.sorted()  // sorted by name because of Comparable<br>let set = Set(users)         // works because of Hashable<br>let isEqual = users[0] == users[1]  // works because of Equatable</pre><p>Conform to these and your type plugs into the entire Swift ecosystem: sorting, sets, dictionaries, diffing, and more.</p><h3>Codable: The Protocol That Replaced Boilerplate</h3><p>Codable is Encodable &amp; Decodable. Conform to it and Swift synthesizes JSON encoding and decoding automatically.</p><pre>struct Article: Codable {<br>    let id: Int<br>    let title: String<br>    let publishedAt: Date<br>    let tags: [String]<br>}<br><br>let json = &quot;&quot;&quot;<br>{<br>    &quot;id&quot;: 1,<br>    &quot;title&quot;: &quot;Swift Protocols&quot;,<br>    &quot;publishedAt&quot;: &quot;2025-08-14T10:00:00Z&quot;,<br>    &quot;tags&quot;: [&quot;swift&quot;, &quot;ios&quot;]<br>}<br>&quot;&quot;&quot;.data(using: .utf8)!<br>let decoder = JSONDecoder()<br>decoder.dateDecodingStrategy = .iso8601<br>let article = try decoder.decode(Article.self, from: json)<br>print(article.title)  // Swift Protocols</pre><p>Three lines to decode a full JSON object into a typed Swift struct. No manual mapping, no stringly-typed dictionary access, no runtime surprises.</p><h3>Protocol-Oriented Programming in Practice</h3><p>The real power shows up in architecture. Here is a testable network layer built entirely on protocols:</p><pre>protocol NetworkService {<br>    func fetch&lt;T: Decodable&gt;(endpoint: String) async throws -&gt; T<br>}<br><br>// Production implementation<br>struct LiveNetworkService: NetworkService {<br>    func fetch&lt;T: Decodable&gt;(endpoint: String) async throws -&gt; T {<br>        let url = URL(string: &quot;https://api.myapp.com&quot; + endpoint)!<br>        let (data, _) = try await URLSession.shared.data(from: url)<br>        return try JSONDecoder().decode(T.self, from: data)<br>    }<br>}<br>// Test implementation - no network required<br>struct MockNetworkService: NetworkService {<br>    var mockData: Data<br>    func fetch&lt;T: Decodable&gt;(endpoint: String) async throws -&gt; T {<br>        try JSONDecoder().decode(T.self, from: mockData)<br>    }<br>}<br>// ViewModel accepts the protocol, not the concrete type<br>class UserViewModel {<br>    private let network: NetworkService<br>    init(network: NetworkService = LiveNetworkService()) {<br>        self.network = network<br>    }<br>}</pre><p>In production: inject LiveNetworkService. In tests: inject MockNetworkService. The view model never knows the difference. This is dependency injection via protocols and it is how testable iOS apps are built.</p><h3>Interview Questions</h3><p><strong>Q: What is a protocol in Swift and how does it differ from inheritance?</strong></p><p>A protocol defines a contract: a set of requirements any conforming type must satisfy. Inheritance copies behavior from a parent class to a child class. Protocols enable composition: a type can conform to many protocols simultaneously, each adding focused capabilities. Unlike inheritance, protocols work with <a href="https://medium.com/@dkvekariya/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659"><strong>structs</strong></a> and <a href="https://medium.com/@dkvekariya/swift-enums-associated-values-raw-values-and-pattern-matching-a5844461beb1"><strong>enums</strong></a>, not just <a href="https://medium.com/@dkvekariya/swift-classes-reference-types-inheritance-and-when-to-use-them-f7a1fd4bd47c"><strong>classes</strong></a>. Swift favors protocols because they are more flexible, more testable, and avoid the fragile base class problems that deep inheritance hierarchies create.</p><p><strong>Q: What is a default implementation in a protocol extension and why is it useful?</strong></p><p>A default implementation is behavior provided in a protocol extension that conforming types automatically inherit without writing any code. It is useful because it lets you add shared behavior to all conforming types at once, allows new protocol requirements to be added without breaking existing conformances, and removes the need for a base class just to share implementation. Conforming types can override the default when they need different behavior.</p><h3>Summary</h3><ul><li>A protocol defines a contract: required properties and methods without implementation.</li><li>Any struct, class, or enum can conform to a protocol.</li><li>Protocol extensions provide default implementations that conforming types inherit for free.</li><li>Protocol composition with &amp; lets functions require multiple capabilities at once.</li><li>Protocols as types enable polymorphism without inheritance.</li><li>Equatable, Comparable, Hashable, and Codable are foundational standard library protocols.</li><li>Protocol-oriented programming powers testable architecture through dependency injection.</li><li>Swift’s standard library, SwiftUI, and Combine are all built on this pattern.</li></ul><h3>Practice</h3><ol><li><strong>Beginner:</strong> Define a Printable protocol with a prettyPrint() method. Create three types that conform to it: Invoice, Receipt, and ShippingLabel. Add a default implementation that prints the type name, then override it meaningfully for each type.</li><li><strong>Intermediate:</strong> Build a Cacheable protocol with var cacheKey: String { get } and var expiresAfter: TimeInterval { get }. Add a default expiresAfter of 300 seconds via a protocol extension. Conform User, Product, and Article <a href="https://medium.com/@dkvekariya/swift-structs-why-apple-chooses-value-types-over-classes-f60b79aa3659"><strong>structs</strong></a> to it with different cache keys.</li><li><strong>Advanced:</strong> Create a Repository&lt;T&gt; protocol with fetch(id: String) async throws -&gt; T, save(_ item: T) async throws, and delete(id: String) async throws. Build a InMemoryRepository&lt;T&gt; struct that conforms to it using a dictionary. Then create a UserService that depends on any Repository&lt;User&gt; and write a test using the in-memory version without touching a network or database.</li></ol><h3>What’s Next</h3><p><strong>Article 13: Swift Extensions: Adding Behavior Without Subclassing</strong></p><p>Protocols define what a type can do. Extensions define what it already does, retroactively. You can extend any type in Swift, including ones from Apple’s frameworks, and add computed properties, methods, and protocol conformances without touching the original source. It is one of the cleanest features in the language.</p><p><em>Part of </em><strong><em>Swift from Zero to Senior</em></strong><em> — a complete iOS engineering curriculum on Medium.</em></p><p><strong>If protocol-oriented programming clicked today, tap 👏 up to 50 times. It helps this series reach developers still building class hierarchies that should be protocol compositions.</strong></p><p><strong>Follow me</strong> so Article 13 lands in your feed automatically. Extensions are next and they make every type in the language feel like yours.</p><p>See you in the next one. 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6b9d48617970" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>