<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Omar 👾</title>
    <description>The latest articles on Forem by Omar 👾 (@obscured_pixels).</description>
    <link>https://forem.com/obscured_pixels</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F615172%2F653e72f0-b3b4-41d1-9f2e-ff62640eef6c.jpg</url>
      <title>Forem: Omar 👾</title>
      <link>https://forem.com/obscured_pixels</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/obscured_pixels"/>
    <language>en</language>
    <item>
      <title>Side Effects with Combine</title>
      <dc:creator>Omar 👾</dc:creator>
      <pubDate>Tue, 20 Apr 2021 14:07:52 +0000</pubDate>
      <link>https://forem.com/obscured_pixels/side-effects-with-combine-2oh3</link>
      <guid>https://forem.com/obscured_pixels/side-effects-with-combine-2oh3</guid>
      <description>&lt;p&gt;One of the benefits of adopting Combine's publisher approach to asynchronous programing is that every operation is a stream or pipeline that we can subscribe and react to via powerful operators. &lt;/p&gt;

&lt;p&gt;This works really well for situations where would like to execute code outside the scope of a publisher as certain events occur. Such executions are often described as side effects&lt;/p&gt;

&lt;h3&gt;
  
  
  What are side effects?
&lt;/h3&gt;

&lt;p&gt;For the context of this article and within the realm of Combine, we can define side effects as invocations that do not transform the output of a publisher which are triggered when certain events occur during a publisher's lifecycle. &lt;/p&gt;

&lt;p&gt;Common use cases for side effects in reactive programming include but are not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Event tracking&lt;/li&gt;
&lt;li&gt;Persisting data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how would we go about implementing side effects in Combine?&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling events
&lt;/h3&gt;

&lt;p&gt;Combine provides a useful &lt;code&gt;handleEvents()&lt;/code&gt; operator that allows us to provide closures that can be performed when certain publisher events occur. This makes it possible, for example, to log relevant information in the event of a non-fatal error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;todoRepository.addTodo(title: title)
    .handleEvents(receiveCompletion: { [logger] completion in
        switch completion {
        case .failure(let error):
            logger.error(error)
            debugPrint("an error occurred: \(error)")
        case .finished:
            debugPrint("addTodo publisher completed")
        }
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the &lt;code&gt;receiveCompletion&lt;/code&gt; parameter, the operator provides other events that we can hook into that can serve a variety of use cases:&lt;/p&gt;

&lt;h4&gt;
  
  
  receiveSubscription:
&lt;/h4&gt;

&lt;p&gt;Executes when the publisher receives the subscription from the upstream publisher. A possible use case for this would be to launch a background process/experience whenever a consumer subscribes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;videoCallProvider.acceptCall()
    .handleEvents(receiveSubscription: { [cameraManager] _ in
        cameraManager.startCapture()
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  receiveOutput:
&lt;/h4&gt;

&lt;p&gt;Executes when the publisher receives a value from the upstream publisher. In the pattern we put together in my previous article &lt;a href="https://obscuredpixels.com/managing-view-state-with-combine"&gt;Managing View State Combine&lt;/a&gt;, we could use this to keep track of Inputs as users interact with our views:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inputSubject
    .handleEvents(receiveOutput: { [eventTracker] input in
        switch input {
        case .addTodo:
            eventTracker.track(.todoAdded)
        case .todoRemoved:
            eventTracker.track(.todoRemoved)
        }
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  receiveCancel:
&lt;/h4&gt;

&lt;p&gt;Executes when the downstream receiver cancels publishing. A good use case for this would be disposing of no longer needed processes that live outside of a publisher's lifecycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;videoCallProvider.acceptCall()
    .handleEvents(receiveCancel: { [cameraManager] in
        cameraManager.endCapture()
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  receiveRequest:
&lt;/h4&gt;

&lt;p&gt;Executes when the publisher receives a request for more elements. Had a hard time thinking of a good use case for this one, but could come in handy during situations where we would like know the amount of outputs being requested by a subscriber.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: closures passed to these parameters are escaped, and as a result, subject to the dangers of strong reference cycles or wrong thread executions. Make sure to avoid strong references by using capture lists and insuring the closure is performed on the appropriate thread via the &lt;code&gt;receive(on:)&lt;/code&gt; operator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  A tip when handling events 💡:
&lt;/h3&gt;

&lt;p&gt;You might have noticed when typing &lt;code&gt;handleEvents&lt;/code&gt;, Xcode will autofill all possible parameters of the method. This can be annoying to deal with, especially if we find ourselves handling specific events frequently. Lets try and fix that with some convenient extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension Publisher {
    func handleOutput(_ receiveOutput: @escaping ((Self.Output) -&amp;gt; Void)) -&amp;gt; Publishers.HandleEvents&amp;lt;Self&amp;gt; {
        handleEvents(receiveOutput: receiveOutput)
    }

    func handleError(_ receiveError: @escaping ((Self.Failure) -&amp;gt; Void)) -&amp;gt; Publishers.HandleEvents&amp;lt;Self&amp;gt; {
        handleEvents(receiveCompletion: { completion in
            switch completion {
            case .failure(let error):
                receiveError(error)
            case .finished:
                ()
            }
        })
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the extensions above, not only will interacting with the operator become more enjoyable, but the end result ends ups looking more readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;todoRepository.addTodo(title: title)
    .handleOutput({ [eventTracker] _ in
        eventTracker.track(.todoAdded)
    })
    .handleError({ [logger] error in
        logger.error(error)
        debugPrint("an error occurred: \(error)")
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In situations where we would need to execute some code along side other asynchronous code, the Combine framework can serve as a good candidate given its elegant approach to performing side effects.&lt;/p&gt;

&lt;p&gt;If you liked this article, &lt;a href="https://twitter.com/obscured_pixels"&gt;follow me on Twitter&lt;/a&gt; for more updates and content about Swift development, architectural patterns and clean code.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
    </item>
    <item>
      <title>Managing View State With Combine</title>
      <dc:creator>Omar 👾</dc:creator>
      <pubDate>Thu, 15 Apr 2021 17:25:06 +0000</pubDate>
      <link>https://forem.com/obscured_pixels/managing-view-state-with-combine-p8k</link>
      <guid>https://forem.com/obscured_pixels/managing-view-state-with-combine-p8k</guid>
      <description>&lt;h3&gt;
  
  
  Data Flow
&lt;/h3&gt;

&lt;p&gt;SwiftUI's built in state management system does a great a job in providing an out of the box data flow solution that alleviates a lot of the pain points associated with manually updating UI based on state changes. &lt;/p&gt;

&lt;p&gt;As your codebase grows and you find yourself leaning towards incorporating common architectural patterns, you'll likely come across the need to separate some state specific logic into a view model. Swift's Combine framework provides some great property wrappers to ease this transition via &lt;code&gt;@PublishSubject&lt;/code&gt; and &lt;code&gt;@ObservedObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are some great articles that go into depth about these topics. I highly suggest you check them out if you aren't yet familiar with these concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://swiftwithmajid.com/2020/02/05/building-viewmodels-with-combine-framework/" rel="noopener noreferrer"&gt;Building ViewModels with Combine framework - Majid Jabrayilov&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.raywenderlich.com/4161005-mvvm-with-combine-tutorial-for-ios" rel="noopener noreferrer"&gt;MVVM with Combine Tutorial for iOS - Rui Peres&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.donnywals.com/using-custom-publishers-to-drive-swiftui-views/" rel="noopener noreferrer"&gt;Using custom publishers to drive SwiftUI views - Donny Wals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Continuing where the articles left off, I've put together a &lt;code&gt;TodoListView&lt;/code&gt; that observes and reacts to a &lt;code&gt;ViewState&lt;/code&gt; published by its &lt;code&gt;ViewModel&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct TodoListView: View {
    @ObservedObject
    private var viewModel = ViewModel()
    var body: some View {
        content(viewModel.viewState)
            .onAppear {
                viewModel.loadTodos()
            }
    }

    @ViewBuilder
    private func content(_ state: ViewState) -&amp;gt; some View {
        switch state {
        case .loading:
            ProgressView()
        case .error:
            Text("Oops something went wrong")
                .padding()
        case .content(let todos):
            List {
                ForEach(todos) { todo in
                    Text(todo.title)
                }
            }
        }
    }
}

extension TodoListView {
    enum ViewState {
        case loading
        case content(todos: [Todo])
        case error
    }

    class ViewModel: ObservableObject {
        @Published
        var viewState: ViewState = .loading
        private let todoRepository = TodoRepistory()
        private var cancellables = Set&amp;lt;AnyCancellable&amp;gt;()

        func loadTodos() {
            self.viewState = .loading
            todoRepository.getTodos()
                .sink { [weak self] completion in
                    switch completion {
                    case .failure:
                        self?.viewState = .error
                    case .finished:
                        ()
                    }
                } receiveValue: { [weak self] todos in
                    self?.viewState = .content(todos: todos)
                }
                .store(in: &amp;amp;cancellables)
        }

        // ....
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup already has some great benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our &lt;code&gt;View&lt;/code&gt; is free of any state management logic. This allows us to unit test and even share that logic between other views&lt;/li&gt;
&lt;li&gt;By conforming to the &lt;code&gt;ObservableObject&lt;/code&gt; protocol and leveraging the &lt;code&gt;@Published&lt;/code&gt; property wrapper, we've managed to make that separation easily consumable by our View. It works very similar to reacting off a &lt;code&gt;@State&lt;/code&gt; property&lt;/li&gt;
&lt;li&gt;We've got a nice repeatable pattern that we can apply to future views that require complex logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While we can definitely call it a day and move on, you might find yourself wondering what other patterns can we apply here that further adhere to the reactive mantra&lt;/p&gt;

&lt;p&gt;I want to highlight that what I'm about to showcase is pretty much a Combine + SwiftUI remix of Jake Wharton's outstanding talk &lt;a href="https://www.youtube.com/watch?v=0IKHxjkgop4" rel="noopener noreferrer"&gt;Managing State with RxJava&lt;/a&gt;. It's about an hour but I can't emphasize enough how amazing his presentation is and how much it inspired me to apply reactive programming to more than just networking and repository logic. It's in Java but thanks to the language's verbosity it's possible to follow along.&lt;/p&gt;

&lt;h3&gt;
  
  
  Room for improvement
&lt;/h3&gt;

&lt;p&gt;Looking at the current state of our view model there are a few things that seem unnatural:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func loadTodos() {
    self.viewState = .loading
    todoRepository.getTodos()
        .sink { [weak self] completion in
            switch completion {
            case .failure:
                self?.viewState = .error
            case .finished:
                ()
            }
        } receiveValue: { [weak self] todos in
            self?.viewState = .content(todos: todos)
        }
        .store(in: &amp;amp;cancellables)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting state outside of the stream seems misplaced and requires one to remember to revert the loading state during success and failure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ..
func addTodo(title: String) {
    todoRepository.addTodo(title: title)
        .sink { [weak self] completion in
            switch completion {
            case .failure:
                self?.viewState = .error
            case .finished:
                ()
            }
        } receiveValue: { [weak self] todo in
            if case .content(var todos) = self?.viewState {
                todos.append(todo)
                self?.viewState = .content(todos: todos)
            }
        }
        .store(in: &amp;amp;cancellables)
}

func removeTodo(id: String) {
    todoRepository.removeTodo(id: id)
        .sink { [weak self] completion in
            switch completion {
            case .failure:
                self?.viewState = .error
            case .finished:
                ()
            }
        } receiveValue: { [weak self] _ in
            if case .content(var todos) = self?.viewState {
                todos.removeAll(where: { $0.id == id})
                self?.viewState = .content(todos: todos)
            }
        }
        .store(in: &amp;amp;cancellables)
}
// ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As our view model grows in functionality, you'll notice our code will quickly get heavy with boilerplate subscription code. While we could clean this up and utilize the&lt;code&gt;assign(to:)&lt;/code&gt; operator, they'd still be another peculiar characteristic of our state management; the lack of a centralized view state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1618389298930%2Fjy1pvpzuS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1618389298930%2Fjy1pvpzuS.png" alt="untitled@2x.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Redux/Flux's unidirectional data flow pattern solves a lot of the complexities of having state mutated throughout various areas in the codebase, yet here we are updating our view state throughout various areas of our view model.  &lt;/p&gt;

&lt;p&gt;How can we adjust our state management approach to alleviate these concerns?&lt;/p&gt;

&lt;h3&gt;
  
  
  Inputs, Actions and ViewState
&lt;/h3&gt;

&lt;p&gt;Looking at our &lt;code&gt;TodoListView&lt;/code&gt; from a behavioral point of view, we can quickly identify some common cause and effect patterns. When a user loads the view, they'd request a list of Todos. When a user adds a Todo, the list will update with the newly added list etc. We could summarize that a user triggered input is causing our app or view model to respond and react to it, resulting in an updated view state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1618389802248%2F3wTfvQzOV.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1618389802248%2F3wTfvQzOV.png" alt="untitled@2x (1).png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sort of pattern is reactive in nature. Inputs can be happening in more than one place at a time and processing those inputs might require async operations. Reactive frameworks like Combine were made for these sort of circumstances and come with some handy operators that can help us gel this pattern into a consumable reactive state.&lt;/p&gt;

&lt;p&gt;Let's see what an implementation that incorporates those operators might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension TodoListView {
    enum ViewState {
        case loading
        case content(todos: [Todo])
        case error
    }

    enum Input {
        case stateRequested
        case todoAdded(title: String)
        case todoRemoved(id: String)
    }

    enum Action {
        case setState(ViewState)
        case addTodo(todo: Todo)
        case removeTodo(id: String)
    }

    class ViewModel: ObservableObject {
        @Published
        var viewState: ViewState = .loading
        private let todoRepository = TodoRepistory()
        private let inputSubject = PassthroughSubject&amp;lt;Input, Never&amp;gt;()
        private var cancellables = Set&amp;lt;AnyCancellable&amp;gt;()

        init() {
            inputSubject
                .flatMap { [todoRepository] input -&amp;gt; AnyPublisher&amp;lt;Action, Never&amp;gt; in
                    switch input {
                    case .stateRequested:
                        return todoRepository.getTodos()
                            .map { todos -&amp;gt; Action in
                                .setState(.content(todos: todos))
                            }
                            .replaceError(with: .setState(.error))
                            .eraseToAnyPublisher()
                    case .todoAdded(let title):
                        return todoRepository.addTodo(title: title)
                            .map { todo -&amp;gt; Action in
                                .addTodo(todo: todo)
                            }
                            .replaceError(with: .setState(.error))
                            .eraseToAnyPublisher()
                    case .todoRemoved(let id):
                        return todoRepository.removeTodo(id: id)
                            .map { _ -&amp;gt; Action in
                                .removeTodo(id: id)
                            }
                            .replaceError(with: .setState(.error))
                            .eraseToAnyPublisher()
                    }
                }
                .scan(viewState) { (currentState, action) -&amp;gt; ViewState in
                    switch action {
                    case .setState(let state):
                        return state
                    case .addTodo(let todo):
                        if case .content(var todos) = currentState {
                            todos.append(todo)
                            return .content(todos: todos)
                        }
                        return currentState
                    case .removeTodo(let id):
                        if case .content(var todos) = currentState {
                            todos.removeAll(where: { $0.id == id })
                            return .content(todos: todos)
                        }
                        return currentState
                    }
                }
                .receive(on: DispatchQueue.main)
                .assign(to: &amp;amp;$viewState)
        }

        func send(_ input: Input) {
            inputSubject.send(input)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are quite a few things going on here, so let's walk through them step by step.&lt;/p&gt;

&lt;p&gt;We first create an entity to describe possible inputs that can occur to our view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    enum Input {
        case stateRequested
        case todoAdded(title: String)
        case todoRemoved(id: String)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These inputs can end up affecting our view state. Let's call these effects actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    enum Action {
        case setState(ViewState)
        case addTodo(todo: Todo)
        case removeTodo(id: String)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to process these inputs in a reactive stream, we create a &lt;code&gt;PassthroughSubject&lt;/code&gt;, which is a subject that broadcasts elements downstream. This works well for our use case as we would like to channel inputs downstream to be processed into possible actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private let inputSubject = PassthroughSubject&amp;lt;Input, Never&amp;gt;()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we init our view model, we subscribe to these emissions and process them via the &lt;code&gt;flatMap&lt;/code&gt; operator. Each input is processed differently. This is why representing our inputs as an enum helps us make sure we account for every possible variation and will remind us in the future to account for newly added inputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inputSubject
    .flatMap { [todoRepository] input -&amp;gt; AnyPublisher&amp;lt;Action, Never&amp;gt; in
        switch input {
        case .stateRequested:
            return todoRepository.getTodos()
                .map { todos -&amp;gt; Action in
                    .setState(.content(todos: todos))
                }
                .replaceError(with: .setState(.error))
                .eraseToAnyPublisher()
        case .todoAdded(let title):
            return todoRepository.addTodo(title: title)
                .map { todo -&amp;gt; Action in
                    .addTodo(todo: todo)
                }
                .replaceError(with: .setState(.error))
                .eraseToAnyPublisher()
        case .todoRemoved(let id):
            return todoRepository.removeTodo(id: id)
                .map { _ -&amp;gt; Action in
                    .removeTodo(id: id)
                }
                .replaceError(with: .setState(.error))
                .eraseToAnyPublisher()
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take note that we are transforming our stream here into a publisher of &lt;code&gt;&amp;lt;Action, Never&amp;gt;&lt;/code&gt;. This means that regardless of the input, the outcome of this step should result in one or many &lt;code&gt;Action&lt;/code&gt;s. The &lt;code&gt;Never&lt;/code&gt; lets the compiler know that we don't intend this subscription to ever error out. In theory it shouldn't. Any error that might occur in processing should be handled and accounted for(i.e displaying an error state in the view). &lt;/p&gt;

&lt;p&gt;This is where the &lt;code&gt;replaceError(with:)&lt;/code&gt;operator comes in to save the day. We can easily transform unexpected errors into a relevant action that will get applied to our view state. It's pretty neat and It always forces us to account for unhappy paths when putting together the view model logic.&lt;/p&gt;

&lt;p&gt;The final piece to the puzzle is the &lt;code&gt;scan&lt;/code&gt; operator. Each action can have an effect on our view state. Via the scan operator, we can process each action as there are emitted by publishers upstream and produce a new view state that we then assign to our &lt;code&gt;@Published&lt;/code&gt; view state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.scan(viewState) { (currentState, action) -&amp;gt; ViewState in
    switch action {
    case .setState(let state):
        return state
    case .addTodo(let todo):
        if case .content(var todos) = currentState {
            todos.append(todo)
            return .content(todos: todos)
        }
        return currentState
    case .removeTodo(let id):
        if case .content(var todos) = currentState {
            todos.removeAll(where: { $0.id == id })
            return .content(todos: todos)
        }
        return currentState
    }
}
.assign(to: &amp;amp;$viewState)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are familiar with reducers, the above should look familiar. Instead of reducing multiple actions into one state, we are processing each action and producing a new state.&lt;/p&gt;

&lt;p&gt;As for our &lt;code&gt;TodoListView&lt;/code&gt;, the only change would be in how our view channels inputs to our view model via the &lt;code&gt;send(_ input: Input)&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ...
content(viewModel.viewState)
    .onAppear {
        viewModel.send(.stateRequested)
    }
// ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we have it. A view state management setup thats a bit more reactive, maybe too reactive. &lt;/p&gt;

&lt;p&gt;Some benefits to this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates to view state are centralized in one area of the view model. This allows to leverage operators like &lt;code&gt;.receive(on:)&lt;/code&gt; and &lt;code&gt;removeDuplicates()&lt;/code&gt; to insure updates are on the main thread and avoid unnecessary view rebuilding&lt;/li&gt;
&lt;li&gt;As we add more inputs and actions, the compiler will complain until you account for them.&lt;/li&gt;
&lt;li&gt;The pattern forces you to account for both the happy and not so happy paths.&lt;/li&gt;
&lt;li&gt;And more that i'll explain in my next post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's quite a bit of stuff going on with this approach. I was super confused when I was first introduced to these concepts. If you find yourself scratching your head, I highly recommend you give the video by Jake a look, as he does a great job in explaining the concept in a lot more detail.&lt;/p&gt;

&lt;p&gt;I hope you found this article useful. This is my first attempt at blogging, so any feedback  and suggestions would be super useful. Follow me on &lt;a href="https://twitter.com/obscured_pixels" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; for future updates and articles.&lt;/p&gt;

&lt;p&gt;In my next post, I'll go over some of the extra benefits of this pattern, namely side effects and how they fit well for related tasks such as event tracking. I'll also share some tips on how to make this approach a lot less boilerplate&lt;/p&gt;

&lt;p&gt;stay tuned.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
