<?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 San Di on Medium]]></title>
        <description><![CDATA[Stories by San Di on Medium]]></description>
        <link>https://medium.com/@sandi1997?source=rss-53587d8aecb4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*ff164iQo1yq7G8zs.</url>
            <title>Stories by San Di on Medium</title>
            <link>https://medium.com/@sandi1997?source=rss-53587d8aecb4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 28 May 2026 17:00:49 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sandi1997/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[The Unidirectional Data Flow and Time Traveling of States in iOS]]></title>
            <link>https://blog.devgenius.io/the-unidirectional-data-flow-and-time-traveling-of-states-in-ios-24698d5d4a55?source=rss-53587d8aecb4------2</link>
            <guid isPermaLink="false">https://medium.com/p/24698d5d4a55</guid>
            <category><![CDATA[redux]]></category>
            <category><![CDATA[unidirectional-data-flow]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[reswift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[San Di]]></dc:creator>
            <pubDate>Tue, 14 Jul 2020 18:06:00 GMT</pubDate>
            <atom:updated>2020-07-16T13:03:07.940Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LF-HtFqMIS5s4067MCaA5w.jpeg" /></figure><p>These days, I’ve been working on a feature like implementing sign up form detail pages which I don’t want to write into database until the flow is complete. Yet I use MVVM pattern for my project which of course is a quite simple and clean architecture, accumulating intermediate state like this leads to singleton abuse and other problems.</p><p>These arise from multiple copies of the state and if you allow your app to navigate back-and-forth, then you have to make sure that the latest state in the latest view controller is available in other view controllers as well. Maintaining the state across all of your controllers that are involved through delegation or callbacks becomes messy. I suppose that kind of problem is quite common among iOS developers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/871/1*gdYxunMUZTfGL9KzGX8qaA.jpeg" /></figure><p>In this case, I chose to integrate Unidirectional Data Flow (Redux) approach with MVVM in my implementation. In the post, I try to explain<strong> work flow of unidirectional data </strong>flow(redux) and <strong>how we can use it for time traveling of state in our app. </strong>Woo hoo! Let’s start… .</p><blockquote><strong><em>Unidirectional data flow</em></strong> is an essential feature for working with the web-based applications.</blockquote><p>The reason data flows from top to bottom is that change detection strategies are also always performed from top to bottom for every single component, every single time, starting from the root component. This is awesome, as unidirectional data flow is more predictable than cycles.</p><h3>So What is Redux and how does it work?</h3><p><a href="https://github.com/rackt/redux">Redux</a> is an alternative or a variation of the <a href="https://github.com/facebook/flux">flux framework</a> that was developed at Facebook, and that Facebook now uses for most of their web applications. The main idea is that <strong>information always only flows in one single direction.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/396/1*45vuFO_dmWn0Wj0VEREoOQ.png" /><figcaption>The unidirectional data flow of redux</figcaption></figure><p>Let’s break down a bit what each component does for our implementation, shall we…</p><ul><li><strong>Views</strong>: Subscribe to <strong>Store</strong> changes and display them on screen. Views send <strong>Actions</strong>.</li><li><strong>Actions</strong>: Actions don’t contain any code and are small pieces of data that describe a state change. An Action is manipulated by a <strong>Reducer</strong>.</li><li><strong>Reducers</strong>: Provide pure functions that based on the current action and the current app state, and return a new app state.</li><li><strong>Store</strong>: Stores the current value of the application state. Other modules like <strong>Views</strong> can subscribe and react to its changes.</li></ul><p>In this article, I’ll use Reswift to implement unidirectional data flow. Reswift is a framework that helps you create Redux-like architecture in swift.</p><p><em>We are going to create an application which fetch popular movie list from network api and include a feature like searching movies. And then we will fetch the search history from redux store after that.</em></p><blockquote>1. First we will need to set up wiring of ReSwift starting from creating states.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a38a2580f6d78ba8acfacb1d9f76d87d/href">https://medium.com/media/a38a2580f6d78ba8acfacb1d9f76d87d/href</a></iframe><p>State is actually a data structure and contains substates like a navigationState<em> (e. g. which view is currently active) </em>and commonly one for each view of your app. In this example, only one AppState contains which involves two substates for 2 views.</p><blockquote>2. We also define two actions, one for adding search result to the store and one for fetching search history according to search keyword.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c805e3802664f48fa53630510f6630f1/href">https://medium.com/media/c805e3802664f48fa53630510f6630f1/href</a></iframe><blockquote>3.Reducer will be notified by the store to return new states depending on difference action types.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4675a1728fee8dfdcfa0b1efd145cad6/href">https://medium.com/media/4675a1728fee8dfdcfa0b1efd145cad6/href</a></iframe><p>In order to have a predictable app state, it is important that the reducer is always free of side effects, it receives the current app state and an action and returns the new app state. Then we wrap our reducers into a main reducer so we can inject into the store all at once.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7e51b2a3d71c676126dd17cb322adf02/href">https://medium.com/media/7e51b2a3d71c676126dd17cb322adf02/href</a></iframe><blockquote>To maintain our state and delegate the actions to the reducers, we need a store. Let’s call it mainStore and define it as a global constant, for example in the app delegate file:</blockquote><pre><strong>var</strong> <em>mainStore</em> = Store&lt;AppState&gt;(reducer: appReducer, state: <strong>ni</strong></pre><blockquote>Before the final step, we need to extend <strong>StoreSubscriber</strong> at our view so the <em>newState</em> method will be called by the <em>Store</em> whenever a new app state is available. This is where we need to adjust our view to reflect the latest app state.</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7ba3ea9aa257040c55f8b2074b9f585c/href">https://medium.com/media/7ba3ea9aa257040c55f8b2074b9f585c/href</a></iframe><p>We all set up. Let’s throw the action dispatch calls, Woo hoo!…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*7_8OuMG7x-tuRX_k9psDOQ.jpeg" /></figure><blockquote>Lastly, our view layer, in this case a view controller, needs to tie into this system by subscribing to store updates and emitting actions whenever the app state needs to be changed:</blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/967535d20c9b877dd1586502f0a0e830/href">https://medium.com/media/967535d20c9b877dd1586502f0a0e830/href</a></iframe><p>As a final result, we can see time traveling ability which help to move back and forth among the previous states of the application and view the results in real time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*ssqmMEdwYZuKPDWIgFoAXQ.gif" /></figure><p>Hope you found this post interesting and useful for your projects. Any question or comment will be welcome!</p><h3>Reference Links</h3><ul><li><a href="https://github.com/ReSwift/ReSwift">GitHub - ReSwift/ReSwift: Unidirectional Data Flow in Swift - Inspired by Redux</a></li><li><a href="https://medium.com/commencis/using-redux-with-mvvm-on-ios-18212454d676">Using Redux with MVVM on iOS</a></li><li><a href="https://medium.com/mackmobile/getting-started-with-redux-in-swift-54e00f323e2b">Getting started with Redux in Swift - Part 1</a></li><li><a href="https://www.raywenderlich.com/516-reswift-tutorial-memory-game-app">ReSwift Tutorial: Memory Game App</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=24698d5d4a55" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/the-unidirectional-data-flow-and-time-traveling-of-states-in-ios-24698d5d4a55">The Unidirectional Data Flow and Time Traveling of States in iOS</a> was originally published in <a href="https://blog.devgenius.io">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS: Hello Repository…]]></title>
            <link>https://medium.com/swlh/ios-hello-repository-b00d7853101e?source=rss-53587d8aecb4------2</link>
            <guid isPermaLink="false">https://medium.com/p/b00d7853101e</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[design-pattern-ios]]></category>
            <category><![CDATA[design-patterns]]></category>
            <dc:creator><![CDATA[San Di]]></dc:creator>
            <pubDate>Thu, 02 Jul 2020 17:13:52 GMT</pubDate>
            <atom:updated>2020-07-02T17:13:52.506Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EGzD3U-B9XPBXlOQAaTfwg.jpeg" /><figcaption>So… repository pattern in ios.. huh?</figcaption></figure><p>Say we have a small code base and includes some codes that fetch data from API and maps into the data model objects. And we also use design pattern like MVP for structuring our project. Aight!… everything is perfect, clean and smooth till now, right? But then suddenly our codebase starts to grow, and you need to write the code to fetch the books over and over again. You might say <em>“let’s copy the code and paste it wherever you need to fetch all the data.”</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*tIFnXmbvax4yBH8i8BUlSA.jpeg" /></figure><p>What if you can provide a single-entry point to work with your models and remove duplicate query code. Here is where “The repository pattern” comes in… .</p><h3>Hello Repository…</h3><p>Repository pattern is a software design pattern that provides an abstraction of data, so that your application can work with a simple abstraction that has an interface. We can assume it as an object that encapsulates all the code to query your models in one place. By adding an abstraction layer over the top of database APIs, we can achieve loose coupling and can keep domain objects <a href="http://deviq.com/persistence-ignorance/">persistence ignorant</a>.</p><p>So, Let’s see how we can integrate repository pattern with generics in an iOS Application. Below, you can take a look at a brief architecture of the application which I don’t suppose it’s a complete one but using this approach will make your app development a lot easier for unit testing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/896/1*HQ5n5FBkmmA7QFS7YvhjxA.png" /><figcaption>Mind my cloud image for networking layer :’(</figcaption></figure><blockquote><strong><em>1. </em></strong><em>We create generic protocol so that it can be used for any model object we have.</em></blockquote><pre>protocol Repository {<br> associatedtype T<br> func getAll() -&gt; [T]<br> func getById(id: Int) -&gt; T<br> func create(newData: T) -&gt; Bool<br> func update(id: Int, newData: T) -&gt; Bool<br> func deleteById(id: Int) -&gt; Bool<br>}</pre><blockquote>2. <em>Then we can infer the type of T to any type of repository object, because by implementing the methods, we have specified what T is. In this case Book object.</em></blockquote><pre>class RemoteRepository: Repository{</pre><pre>   let remoteDataSource: RemoteDataSource</pre><pre>   init(dataSource: DataSource){<br>        self.remoteDataSource = dataSource<br>   }</pre><pre>    func getAll() -&gt; [Book] {<br>        return remoteDataSource.getAll()<br>    }<br>    <br>    func getById(id: Int) -&gt; Book {<br>        return remoteDataSource.getById(id)<br>    }<br>    <br>    func create(newData: Book) -&gt; Bool {...}<br>    <br>    func update(id: Int, newData: Book) -&gt; Bool {...}<br>    <br>    func deleteById(id: Int) -&gt; Bool {...}<br>}</pre><blockquote>3. Data and Networking Layer</blockquote><pre>//Networking layer<br>class BookStoreApi{<br>  class func saveNewBook(book: BookRequest){</pre><pre>    // save new book data to Server using Alamofire/UrlSession          </pre><pre>    Alamofire.request(...) <br> }</pre><pre>  class func getAllBooks() -&gt; Observable&lt;Book&gt; {<br>    // get all books from Server using Alamofire/UrlSession ...<br>  }<br>}</pre><pre>//Data layer<br>class RemoteDataSource{<br> class func getBookData() -&gt; Observable&lt;Book&gt; {<br>        // return an Observable BookData from Server<br>    }<br>    <br>    // Saves the Observable data into Remote Server<br>    class func saveBookData(_ data: Book) {<br>        // ...<br>    }<br>}</pre><p>BookListViewModel holds references of repositories and communicates with the BookListViewController when needed. Finally, in your view controller you can update your UI with the fetched data.</p><h3>When and why we use repository pattern in our code base?</h3><p>Repository Pattern is highly useful when you need to work parallel with different data sources such as Remote, Local and Cache. It is also architecturally useful when it comes to Separation of Concerns Principle. It makes your program testable and flexible.</p><h3>When it becomes overkill feature?</h3><p>Though using repository pattern has loads of benefits, there are also couples of considerations to be aware of before overusing it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*ADcTPcPoZr_y_3aycGgrLQ.jpeg" /></figure><p>This is ‘pre-emptive work’. You’re doing a lot of work up front, <em>just in case</em> you might change your mind down the line. Trying to architect a ‘generic’ database solution which you may never end up using sounds like it might not pay off.</p><p>You’re increasing app complexity. This means more potential for bugs and more rigorous testing would be needed to make sure your API and the database API are in sync.</p><p>As long as the new database you’d be moving to consists of managing objects as well (ie Core Data), converting from one database to another isn’t usually a lot of work. As such, I’d recommend avoiding unnecessary work until the time when it becomes necessary.</p><h3>Recap</h3><p>Although extra layer of abstraction can lead unnecessary complexity for the development, adding a layer over the top of database APIs is pretty common. In order to hide the API from their business logic code, most developers usually wrap data layer with their own classes.</p><p>Hope you found this post interesting and useful for your projects. Any question or comment will be welcome!</p><h4>Reference Links</h4><p><a href="https://medium.com/@frederikjacques/repository-design-pattern-in-swift-952061485aa">https://medium.com/@frederikjacques/repository-design-pattern-in-swift-952061485aa</a></p><p><a href="https://medium.com/tiendeo-tech/ios-repository-pattern-in-swift-85a8c62bf436">https://medium.com/tiendeo-tech/ios-repository-pattern-in-swift-85a8c62bf436</a></p><p><a href="https://medium.com/swlh/theoretical-usage-of-repository-pattern-with-rxswift-and-mvvm-a3dfebb940ce">https://medium.com/swlh/theoretical-usage-of-repository-pattern-with-rxswift-and-mvvm-a3dfebb940ce</a></p><p><a href="https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html">https://www.infoworld.com/article/3117713/design-patterns-that-i-often-avoid-repository-pattern.html</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b00d7853101e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/ios-hello-repository-b00d7853101e">iOS: Hello Repository…</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>