<?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 Marko Aras on Medium]]></title>
        <description><![CDATA[Stories by Marko Aras on Medium]]></description>
        <link>https://medium.com/@markoaras?source=rss-249f17055a4d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*9xuADIPZKVp8QgXp-1W9Fg.png</url>
            <title>Stories by Marko Aras on Medium</title>
            <link>https://medium.com/@markoaras?source=rss-249f17055a4d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 06:48:55 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@markoaras/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[Real-Life Magic in the Making: Meet the Apple Vision Pro]]></title>
            <link>https://medium.com/arasdigitalproducts/real-life-magic-in-the-making-meet-the-apple-vision-pro-2abf0331729d?source=rss-249f17055a4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/2abf0331729d</guid>
            <category><![CDATA[apple-vision-pro]]></category>
            <category><![CDATA[visionos-app-development]]></category>
            <dc:creator><![CDATA[Marko Aras]]></dc:creator>
            <pubDate>Thu, 29 Feb 2024 20:43:58 GMT</pubDate>
            <atom:updated>2024-03-01T09:36:59.390Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GY9s1cTUnNDGcrCdaN4bCA.png" /></figure><p>The long-awaited spatial computer that seamlessly blends digital content and apps into physical space, enabling eyes, hands, and voice navigation, is finally here. And when we say here, we mean in our very own hands. We are so excited to use this revolutionary product, but we are even more excited about the opportunities that come with it.</p><p><strong>Features of the Future</strong></p><p>We’ll single out only some of them, not to overload you with the product details that Apple so beautifully outlined <a href="https://www.apple.com/apple-vision-pro/">here</a>. Building on the existing macOS, iOS, and iPadOS, the visionOS enables spatial experiences. This fantastic new computer provides you with an infinite canvas where you can move, arrange, and scale your apps to create a workplace you’ve always dreamed about while still staying present in the world surrounding you. The Apple Vision Pro camera is something else: it’s the first 3D camera from Apple, making spatial photos and spatial audio a reality. In addition, the Vision Pro offers more pixels than a 4K TV for each eye, so any space you’re in transforms into a personal theater to enjoy your video and audio content in the most magical way possible.<br> <br>According to <a href="https://www.forbes.com/sites/timbajarin/2023/08/29/how-long-has-apple-been-working-on-its-vision-pro-headset/">Forbes</a>, the first patent related to the technology used in Apple Vision Pro dates back to 2007, when the iPhone was introduced. In particular, it was a patent related to a head-mounted display, as <a href="https://www.patentlyapple.com/2023/08/apple-won-a-patent-today-covering-their-original-apple-vision-related-invention-dating-back-to-2007-the-year-of-the-iphone.html">Patently Apple</a> reports: Using one or more optical and digital components, the personal display device may adjust displayed media to overlay features of a theater, stadium, or concert facility, thus giving the user of the individual display device the impression of being in the facility. Since Apple Vision Pro has been in the works for well over a decade, dare we think what Apple might have in store for us for the next couple of decades? Whatever it may be, we’ll be ready for it just like we’re ready for this fantastic new spatial computer today.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-VPT8jqFggXirS40yfqpEg.png" /></figure><p><strong>Creating New Realities with visionOS</strong></p><p>Our team couldn’t wait to get their hands on the <a href="https://support.apple.com/en-gb/guide/apple-vision-pro/tan39b6bab8f/1.0/visionos/1.0">Vision Pro</a>, but they are also more than ready to start building apps for it, considering the fantastic new features we now finally have a chance to use, explore, review, and build on. In addition, reimagining our client’s needs in the context of spatial computing is something that we’ve been looking forward to for a long time now, and it’s definitely a pathway for our clients to gain the upper hand.</p><p><em>At Aras™️ Digital Products, we don’t just peek into the future; we sculpt it. Our vision extends beyond screens and pixels — it dances in the ethereal glow of spatial computing. Imagine a symphony of code and light orchestrated by the Apple Vision Pro, our cosmic wand. This isn’t mere technology; it’s alchemy. With every line of code, we weave immersive tapestries that whisk our users across time and space. <br>Remember those dusty reels of old HNK Hajduk matches? Well, now you’re not just a spectator; you’re a time-traveling aficionado, reliving the crowd’s roar and the thrill of victory. And bathrooms? Oh, they’re no longer mundane. With a dash of spatial magic, you’ll design your Kohler sanctuary — a fusion of elegance and functionality. The tiles align, the faucets hum, and the mirror winks at your reflection, whispering secrets of serenity. But wait, there’s more. Buckle up because you’re about to test-drive a Porsche — not on asphalt, but in the nebulous expanse of our digital realm. Feel the purr of the engine, the wind tousling your virtual hair, and the thrill of acceleration. And when you step out, you’ll carry that exhilaration into the real world.<br>At Aras™️ Digital Products, we don’t ask what kind of app you need; we ask what universe you want to inhabit. The Apple Vision Pro is our stardust, and we’re here to make your cosmic dreams a pixel-perfect reality</em>. <br>– William Sullivan, Business Development, Aras™️ Digital Products</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1775pQWQ-5pRukBRa8SLMg.png" /></figure><p><strong>Reimagining Art</strong></p><p><em>The visionOS offers tremendous potential when it comes to every aspect of art. And that is where we step in to shape the future: we want to explore and build on the space in which art and technology meet, where they co-exist, intertwine, and blend. If you are an artist with ideas that go along these lines, you have to let us know so that we can start creating something fantastic together and make the most of the spatial computing era.</em></p><p><em>It will be exciting to see creativity and cutting edge technology come together with Apple Vision Pro. We passionately believe that uniting art and technology is a path to greatness and we are ready to take it. Our commitment to innovation is an important part of our work which keeps our imagination going, allowing us to see no boundaries when it comes to design and development.</em> <br>- Ivan Aras, Head of Design at Aras™ Digital Products</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XZkdUfjpBWos_vXf9KbcrA.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2abf0331729d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arasdigitalproducts/real-life-magic-in-the-making-meet-the-apple-vision-pro-2abf0331729d">Real-Life Magic in the Making: Meet the Apple Vision Pro</a> was originally published in <a href="https://medium.com/arasdigitalproducts">Aras™ Digital Products</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Screenshots automation for iOS with Bitrise & Fastlane]]></title>
            <link>https://medium.com/arasdigitalproducts/screenshots-automation-for-ios-with-bitrise-fastlane-5899eeb3d6b?source=rss-249f17055a4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/5899eeb3d6b</guid>
            <category><![CDATA[fastlane]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[screenshots]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[bitrise]]></category>
            <dc:creator><![CDATA[Marko Aras]]></dc:creator>
            <pubDate>Fri, 17 Apr 2020 09:20:32 GMT</pubDate>
            <atom:updated>2022-01-20T09:13:59.893Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*04zvAMwXKFvctzA1n7g66Q.png" /></figure><h3>Screenshot automation on iOS with Bitrise &amp; Fastlane</h3><p>Screenshot automation is an important feature if you need to make sure everything is displayed properly on all the variations of languages and screen sizes. This can save you a huge amount of time testing all these cases.<br>I spent some time trying to find the best tool to do this and since I’m using Bitrise for CI/CD I wanted to keep everything in the same channel.</p><p>For running UI Tests on real devices, I’m using Firebase Test Lab, but it doesn’t support making screenshots for iOS (for Android apps FTL is a good solution).</p><p>I’m going to use the iOS project named <em>ScreenshotAutomation</em> with UITests included for this example and a new Bitrise project named <em>ScreenshotAutomation</em>.</p><h3>Fastlane</h3><p>The first step we need to do is add the Fastlane to this project and set it up for making screenshots.</p><p>Make sure you have the <a href="https://docs.fastlane.tools/getting-started/ios/setup/">Fastlane installed</a> and in the terminal just run `<em>fastlane</em>` in the project root folder.</p><p>This will start to configure Fastlane for your project, you just have to follow the steps provided.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/713/1*HBI4zZuDX9CZtrs9DXdb9g.png" /><figcaption>Fastlane setup</figcaption></figure><p>Don’t forget to <a href="https://www.talentica.com/blogs/ios-build-management-using-custom-build-scheme/">create a new Schema</a> and mark it as <em>Shared</em>. I named it <em>FastlaneScreenshotAutomation</em>.</p><blockquote>Your project should look like this</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D_AsDoOPywXYVyx4OxbVYw.png" /><figcaption>Project layout</figcaption></figure><p>Now you can continue with Fastlane setup. Select the new schema you created.</p><p>I’m not going to use these screenshots for App Store Connect so I’ll skip this step.</p><p>This will create a new <em>Fastlane</em> directory in your project. There are two here that we are going to need.</p><p><strong>Snapfile</strong> — configuration for our screenshots</p><p><strong>Fastfile</strong> — defines the <em>lanes</em> that Fastlane can use</p><p>In the Snapfile, I’m only going to set up the English language and a few screen sizes. However, this file allows for more configuration and I encourage you to check it out.</p><p>This is what my Snapfile and Fastfile look like</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/995/0*yGXAPHRNo8wJ8bgV" /><figcaption>Snapfile and Fastfile</figcaption></figure><p>You can always check available Lanes with `<em>fastlane lanes</em>` command and run the lane with `<em>fastlane [lane_name]</em>`. We have just one lane, named `<em>screenshots</em>` as you can see in the `<em>Fastfile`</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/716/1*BJM8xt7w-2YOoYLgIaNSxg.png" /><figcaption>Available lanes</figcaption></figure><p>Run this lane and it will create your first screenshots. Make sure your iOS version is properly set for <em>ScreenshotAutomationUITests</em> target (<em>Build Settings -&gt; iOS Deployment Target</em>) and that your Schema looks like this. Also, I opted out of using Scene Delegate since that can cause some problems.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_ap3MmLy6W2nyt0m_6L3Xg.png" /><figcaption>Schema</figcaption></figure><p>This is our final result</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/588/0*eeDouYbBTBiOJFXd" /><figcaption>Screenshots directory</figcaption></figure><p>You can also add some more options to Snapfile. You can find the list of the options by running <em>fastlane action</em> <em>snapshot</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*ZSoIvxAImRVGsM0y6JbDQQ.png" /><figcaption>Snapfile configuration</figcaption></figure><p>I suggest that you add screenshots directory to <em>.gitignore</em> as this is not something you would need in your repo.</p><h3>Bitrise</h3><p>For the Bitrise part, I created a new project, connected my <a href="https://github.com/arasmarko/ScreenshotAutomation">GitHub repo</a> (make sure you pushed all the changes from above).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*eb0tyl8DciHaksri" /><figcaption>Project build configuration</figcaption></figure><p>You can skip adding the app icon and webhooks in project setup.</p><p>Now we have to create a workflow for screenshots on Bitrise. This should already be done by default and it should look like the image below. I also like to enable verbose logging on the fastlane step until I make sure everything is working fine. To make sure our screenshots are exported correctly we have to try out a build.</p><p>This should be in <strong>Build - Apps &amp; Artifacts</strong>. If you can’t find your screenshots make sure you add the correct <em>Input variables </em>in the <em>Deploy to Bitrise </em>step. I like to compress my artifacts so I set this to true. You can find the exact value for <em>Deploy directory or file path</em> by checking where your screenshots.html is stored in your build log. For me it us <em>/Users/vagrant/git/screenshots</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/740/1*-O3LYEOQz8-2DhTy21ud3A.png" /><figcaption>Deploy to Bitrise Step</figcaption></figure><p>In the end, it should look something like this</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/734/1*2wIQNUDEQpbsf_5_RUxGGw.png" /><figcaption>Final result</figcaption></figure><p>Your build will take some time, so be patient, but your final results will be worth it and this could save you quite some time in the future. You can also add triggers to this build whenever you want so make sure you investigate all that Bitrise offers.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5899eeb3d6b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arasdigitalproducts/screenshots-automation-for-ios-with-bitrise-fastlane-5899eeb3d6b">Screenshots automation for iOS with Bitrise &amp; Fastlane</a> was originally published in <a href="https://medium.com/arasdigitalproducts">Aras™ Digital Products</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[MVVM with RxSwift]]></title>
            <link>https://markoaras.medium.com/mvvm-with-rxswift-88561b4b1046?source=rss-249f17055a4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/88561b4b1046</guid>
            <category><![CDATA[rxswift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[mvvm]]></category>
            <dc:creator><![CDATA[Marko Aras]]></dc:creator>
            <pubDate>Fri, 28 Sep 2018 08:56:04 GMT</pubDate>
            <atom:updated>2018-09-28T08:56:04.274Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C_nQpqs8PqTtCaI9dQOZhw.png" /></figure><p>Using MVVM instead of MVC, Apple’s default architecture, has turned out to be a good choice for me. I would like to show you some problems that I ran into using MVVM with RxSwift and some solutions that made my life easier.</p><p>In this article, I would like to show you a few things about using the Model-View-ViewModel (MVVM) architecture with RxSwift. We’ll cover a few concepts that made my life a whole lot easier, but also show you some problems that I ran into. When setting up a new iOS project, Xcode defaults to using the Model-View-Controller (MVC) architecture. Switching to MVVM has turned out to be a good choice for the projects I work on.</p><p>👉 <em>If you are familiar with the concept of MVVM you can skip to the examples section below.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/17/1*lkfzztxmkppJifm7E_7EEw.png" /></figure><h3>Comparison between MVC and MVVM</h3><p>Before getting started with MVVM, I’ve used MVC as my default architecture. The easiest way to get started with MVVM was to compare it against MVC, so I think that might be a good way to familiarize ourselves with it.</p><p>Let’s consider the general idea and flow behind MVC.</p><ul><li>The <em>View</em> handles some sort of user action by pinging the <em>Controller</em>.</li><li>The <em>Controller</em> is in charge of updating the <em>Model</em> with the data received from the <em>View</em>.</li><li>The <em>Model</em> handles any data changes and notifies the <em>Controller</em>.</li><li>The <em>Controller</em> updates the <em>View</em>.</li></ul><p>The diagram below should make things a bit clearer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5QsATgQuD4jZqzm48lLefA.png" /><figcaption>Model-View-Controller</figcaption></figure><p>In the case of web development, where you have a clear separation of these three layers, this sounds great! But when developing for iOS, things can get a little more messy.</p><p>It is easy enough for us to separate the <em>Model</em> and that stays the same for both MVC and MVVM.</p><p>It gets a little bit more complicated when we try to separate the <em>View</em> and <em>Controller</em> parts. If you have been using MVC in iOS you must have noticed that we are missing something. Where are our <em>View</em> and <em>Controller</em> layers? We have the <em>ViewController</em> that <strong>should</strong> act as a <em>View</em>, yet we still write a <strong><em>huge amount</em></strong> of business logic, data manipulation, networking and UI inside of that <em>ViewController</em>. Even for the most basic of screens, our <em>ViewController</em> can get pretty big, resulting in two things.</p><ol><li>A huge amount of code that is very hard to maintain.</li><li>It is almost impossible to test anything in this mess because our presentation mixes with business logic.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r9OUKXiaFfD15v2rw-f4Pw.png" /><figcaption>Model-View-Controller (iOS)</figcaption></figure><p>What if we separate this mess into two distinct and separate layers, making the <em>ViewController </em><strong><em>responsible only for the UI</em></strong> and some other layer responsible for the business logic. That is exactly what MVVM does. It introduces the <em>ViewModel</em> as a layer between the <em>View</em> and the <em>Model</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rEqrSwtmZ4Aru1XKJ-fsrw.png" /><figcaption>Model-View-ViewModel</figcaption></figure><p>The responsibilities of the <em>ViewModel</em> are to update the Model and prepare the data for the <em>View</em>. A great thing with MVVM is that the <em>ViewModel</em> provides some kind of <strong><em>data binding</em></strong> for the <em>View</em> so it can update automatically on any data change. There are a few ways to implement data binding on the <em>ViewModel</em>: delegates, Key-Value Observing, Reactive Programming and some others.</p><p>My favorite approach is Reactive Programming using <a href="https://github.com/ReactiveX/RxSwift"><strong>RxSwift</strong></a>. If you are new to the Rx world you might have some problems following along with the examples, so I recommend you come back here after you read more about it. Or you can continue reading and ignore the syntax, just try to get your head around the idea and how things work.</p><p>👉 Quick tip: The <em>ViewModel</em> should never have a reference neither to the <em>View</em>, or any <em>UIView</em> subclasses. As a rule of thumb: <strong>if you import <em>UIKit</em> you are doing something wrong.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/17/1*lkfzztxmkppJifm7E_7EEw.png" /></figure><h3>🛠 Examples</h3><p>The best way to make all this a bit clearer is to demonstrate it in a simple example. Some things we are going to cover:</p><ul><li>how data binding works,</li><li>the convenience of <em>flatMapLatest</em>,</li><li>a few problems I stumbled upon.</li></ul><p>Download the project so you can follow along. If you are unfamiliar with some of the libraries I used, just ignore them, they are not relevant to what I’m about to show.</p><p>⬇️ Download the example project <a href="https://github.com/arasmarko/mvvm-rx-demo"><strong>here</strong></a>.</p><h4>Binding</h4><p>👉 Make sure you are checked out in the <em>master</em> branch.</p><p>Once you start the app you are presented with a table populated with a list of developers. Selecting any of them sends you to the Developer screen. On this screen, we have a counter and a button that increases the counter. Pretty useless app, but that’s not the point. 😇</p><p>Open the <em>DeveloperViewController</em>, and the <em>DeveloperViewModel</em> files. We are going to bind the text presented in the label to correspond to data from the <em>ViewModel.</em> We are also going to bind the <strong>+</strong> button taps so we can increase the counter.</p><p>On lines 30 and 31 in the <em>DeveloperViewController</em>, we are creating an <em>Observable</em> that is going to emit an event every time the user taps the <strong>+</strong> button.</p><pre>let increaseCounterTaps = increaseCounterButton.rx<br>    .tap<br>    .asObservable()</pre><pre>self.developerViewModel<br>    .setupIncreaseTaps(increaseCounterTaps: increaseCounterTaps)</pre><p>In the <em>DeveloperViewModel</em> we are listening to these events, increasing the counter every time it happens, and binding those changes to the counter <em>Driver</em>. We are doing this so we can listen to these changes in the <em>ViewController.</em> <strong>This is the data binding we were talking about before.</strong></p><pre>func setupIncreaseTaps(increaseCounterTaps: Observable&lt;Void&gt;) {<br>    counter = increaseCounterTaps<br>        .do(onNext: { [weak self] a in<br>            self?.counterState += 1<br>        })<br>        .flatMap { [weak self] _ -&gt; Observable&lt;String&gt; in<br>            guard let `self` = self else {<br>                return Observable.just(&quot;0&quot;)<br>            }<br>            return Observable.just(&quot;\(self.counterState)&quot;)<br>        }.asDriver(onErrorJustReturn: &quot;0&quot;)<br>}</pre><pre>func setupObservables() {<br>    developerViewModel.counter<br>        .drive(self.counterLabel.rx.text)<br>        .disposed(by: disposeBag)<br>}</pre><h4>flatMapLatest</h4><p>In this part, I’ll show you how the <em>flatMapLatest</em> operator works on the search example. For this part, I’ve built a <em>DataService</em> service that simulates fetching data from the remote server. As is often the case in the real world, every response from the server has some delay. To demonstrate this better, the delay is a bit bigger than your server response should usually be!</p><p>The idea here is that with every new letter typed in the search bar, we are asking the server for results for the corresponding term. At any given moment we want to present results for the last term inputted. So imagine you are searching for a developer named “John”. The last two searches are for “Joh” and “John”. If response for “Joh” comes <strong>after</strong> the response for “John”, we have to ignore it.</p><p><em>flatMapLatest</em> is the <strong>ideal solution for our problem</strong>. The corresponding image is shown below and for code check the following files: <em>HomeViewController</em>, <em>HomeViewModel</em>, and <em>DataService</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cIyQDe-GApRvKyU0wYgekg.png" /><figcaption>flatMapLatest</figcaption></figure><h3><strong>🤦‍ Problems</strong></h3><p>The last thing I want to touch upon are the most common problems that come up when using MVVM and RxSwift, and some of these have given me a lot of headaches. They can result in both bugs and crashes with your application.</p><h4><strong>Drivers</strong></h4><p>👉 Documentation for the <em>Driver</em> trait can be found <a href="https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Traits.md#driver"><strong>here</strong></a>.</p><p>Use Driver when you are binding to the UI elements, it ensures you don’t touch UI from anywhere but the main thread and saves you from unnecessary crashes. It’s easy to change threads and even easier to forget about it and by using Drivers you don’t have to worry about going back to main thread before interacting with the UI.</p><p>You can find the example on the branch named <em>no-driver-problem</em>, just run it and try tapping on the <strong>+</strong> button in <em>DeveloperViewController</em> and see what happens.</p><h4><strong>Dispose Bag</strong></h4><p>Dispose Bag is there for you so you don’t have to worry about disposing subscriptions. Usually, this is done when the ViewController is removed from memory. But sometimes that is not the right time to dispose and the best example for that are the cells in the table view.</p><p>If you are adding disposables from a cell into tableView’s disposeBag, when the user starts to scroll and cells start to reuse, you are going to end up with multiple outdated subscriptions. This usually results in multiple calls to the method in charge of handling cell selection.</p><p>Example for using the wrong DisposeBag is on the <em>wrong-dispose-bag</em> branch, in the <em>setupTableView</em> method of the <em>HomeViewController</em>. Try scrolling the table on HomeViewController to get some cells reused, and keep an eye on the lines that get printed out.</p><h4><strong>Variables and PublishSubjects</strong></h4><p>When I first started using RxSwift everything seemed like it should be a Variable. That is because they bring mutability to the immutable world, but in most cases that is not good and they can be changed with some Observable. Use them with caution.</p><h4><strong>Retain cycle</strong></h4><p>I left this one for the end. I love it as much as I hate it. As we said before, dispose is called on <em>deinit</em>. But what if <em>deinit</em> doesn’t happen? This is a general problem with closures in Swift, but this example demonstrates it in the context of Rx.</p><p>Let’s start from the top to understand the problem. The <em>ViewController</em> has a reference to the <em>DisposeBag</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CI2FqoqhcJfVZYGQg2XvuQ.png" /><figcaption>VC -&gt; DB</figcaption></figure><p>By adding <em>Disposable</em> to the <em>DisposeBag</em> we are giving a DB reference to the <em>Disposable</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HIGCroy09mZh7ME_ZBh7qA.png" /><figcaption>VC &gt; DB &gt; Disposable</figcaption></figure><p>The <em>Observable</em> lives within <em>Disposable</em> so <em>Disposable</em> has a reference to it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-CZQ-3F_1v-N2emhCB2QKA.png" /></figure><p>If we use <em>self</em> inside <em>Observable</em> we are giving the <em>Observable</em> a strong reference to the VC and that results in the following retain cycle.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aMPH693AlAd9nWi5qu8__Q.png" /></figure><p>There are a few solutions to this problem, and they are all based on breaking the strong reference from Observable to VC.</p><ul><li>We can pass variables we are going to use to the capture list. I don’t like this one because it can get messy when using more than one variable.</li><li>We can use <em>unowned</em> self but the problem here is if something goes wrong it results in crash.</li><li>❤️ My favorite one is making <em>self</em> `<em>weak`</em> and providing what happens if <em>self</em> is <em>nil, </em>like you can see in the `setupIncreaseTaps` function. <strong>Bulletproof!</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/17/1*lkfzztxmkppJifm7E_7EEw.png" /></figure><p>This was my insight on MVVM with RxSwift, feel free to clap, share and comment. Thank you for your time, looking forward for any constructive criticism 🙂.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=88561b4b1046" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Testing MVVM with RxSwift code]]></title>
            <link>https://medium.com/arasdigitalproducts/testing-mvvm-with-rxswift-code-2f99ededea63?source=rss-249f17055a4d------2</link>
            <guid isPermaLink="false">https://medium.com/p/2f99ededea63</guid>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[rxswift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Marko Aras]]></dc:creator>
            <pubDate>Fri, 28 Sep 2018 08:55:49 GMT</pubDate>
            <atom:updated>2021-06-29T07:27:14.001Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xBTVVbEqaFN-RbkECTs3JQ.png" /></figure><p>I don’t wanna waste your time explaining why writing tests is important since I suppose you already know enough about this if you came across this article.</p><p>I recommend reading the chapter about testing from Uncle Bobs <em>Clean Code</em> where he explains why is testing important in his own way, and why is it important to keep tests clean. He also explains five rules called F.I.R.S.T. in a bit more details. Let’s just keep in mind that test should be<strong> Fast, Independent, Repeatable, Self Validating, Timely.</strong></p><p>We are using MVVM architecture, and you can read more about it in my <a href="http://arsfutura.co/magazine/mvvm-with-rxswift/">blog post</a>.</p><p>There are many different types of testing but this article is going to focus on the <strong>unit</strong> and <strong>integration</strong> tests.</p><h3>My experience: <strong>How writing tests made me a better developer</strong></h3><p>You can absolutely skip this chapter if you are here just for the code or you want to see the way we implemented tests with RxSwift. I won’t even be mad, I just want to share my story about getting into writing tests and why it was useful to me.</p><p>I’m not ashamed to admit that this was my first big project where we decided that we are going to write tests. In the college, there were at least five courses where I was learning about the importance of testing, rules, benefits, etc., but I never fully understood how powerful testing can be. I even wrote tests for the several college projects but I was always writing them with just making them pass in mind, never have I thought about benefiting from them. They were there just so I can say “I’m writing test“ to make me look like a better developer or to meet the project requirements. How young and naive was I? And that was not that long ago.</p><p>With getting the new project we decided that this will be the project where we as a team want to take our skills to the new level, with great code coverage, unit, integration, and UI test, and same dedication for tests as for code, architecture, and design.</p><h4>Writing first tests</h4><p>So a decision was made and the time has come to start writing tests. We are not doing Test Driven Development so what I tried to do is write tests for the Login feature that I was working on already. The feature was almost done and I wanted to write tests for it to make sure if anything changes in the future, the changes don’t break anything, and if they do, to pinpoint to what is broken. Figuring out why would be much easier then.</p><ul><li>First time I created a new test class in the project using RxSwift I was pretty confused. I wanted to test observables in the view model, but I had no idea how to do it, how to make it a unit and not an integration test, how to simulate events from view controller etc.</li></ul><p>I tried to write <strong>unit tests</strong> for <strong>LoginViewModel</strong>. Let’s see what this means.</p><ul><li><strong>Unit tests</strong> — the lowest level of software testing where individual components — <strong>units </strong>are being tested. In this case, our unit is LoginViewModel, and writing tests for this unit mean that all the dependencies must be mocked and all the tests must depend <strong>only </strong>on LoginViewModel code.</li><li>What that means in our MVVM architecture is that we want to tests each layer and every component for itself. So each ViewController, ViewModel , and Model has to have its own tests. For each component in our architecture, we need to have an associated test suite. Basically, you want to isolate and test each of your classes separately. All the services, managers etc. should be tested on its own, and have mocks that can be injected into the class that is using them.</li><li>My LoginViewModel was depending on the few classes, like NetworkingService and ValidationService. Something like this.</li></ul><pre>class LoginViewModel {<br>    private let networkingService = NetworkingService()<br>    private let validationService = ValidationService()<br>    <br>    ...</pre><pre>}</pre><ul><li>Looking at the code above makes me sick in the stomach now, because this code is hardly reusable or testable. How do you write mocks for these dependencies? The answer is <strong>protocols </strong>and<strong> dependency injection</strong>!</li></ul><pre>class LoginViewModel {<br>    private let networkingService: NetworkingServiceProtocol<br>    private let validationService: ValidationServiceProtocol<br>    <br>    init(networkingService: NetworkingServiceProtocol,<br>         validationService: ValidationServiceProtocol) {</pre><pre>        self.networkingService = networkingService<br>        self.validationService = validationService<br>    }<br>    <br>    ...</pre><pre>}</pre><p>Swapping concrete implementations with interfaces allows us to write mocks much easier. Our mocks now just have to implement these protocols and we can do that with ease. And we no longer depend on the implementation of these services in our tests and now these tests can be called <strong>unit</strong> tests.</p><p>Once I wrote all the unit tests I start writing <strong>integration tests</strong> to see if different parts of the system work as they should when they interact with each other.</p><p><strong>Integration tests</strong> — the next level of software testing after unit testing, This is the place where you want to test the interaction between integrated components in your system. Take ViewController and ViewModel for example. After we wrote isolated tests for SomeViewController, and for SomeViewModel, we need to test do these components work as they should once they interact with each other. This interaction in our MVVM architecture is implemented using RxSwift.</p><p>Writing integration tests now should be easy, like playing with legos, since you just connect components that you want to connect and use mocks for the others.</p><p>We have testers dedicated to writing UI tests using Appium so I’m not going to write about that since I have very basic knowledge of this.</p><h3>Testing Rx code</h3><p>When we started writing tests for our architecture we got stuck immediately, and the reason for this were <strong>bindings</strong> of <em>View Controllers</em> and <em>View Models. </em>The way we used to implement these bindings is that we would initialize View Model with Observables we needed to handle, or we would just assign them along the way, something like this:</p><pre>class SomeViewModel {<br>    var counter: Driver&lt;String&gt;!</pre><pre>    init(increaseCounterTaps: Observable&lt;Void&gt;) {<br>        counter = increaseCounterTaps<br>            .flatMap<br>            ...<br>    }</pre><pre>}</pre><p>or like this:</p><pre>class SomeViewModel {<br>    var counter: Driver&lt;String&gt;!</pre><pre>    func setupIncreaseTaps(increaseCounterTaps: Observable&lt;Void&gt;) {<br>        counter = increaseCounterTaps<br>            .flatMap<br>            ...<br>    }</pre><pre>}</pre><p>Soon we figured out that it was a nightmare to write tests for something like this. A solution we came up with was to switch from Observables to PublishSubject since it is much easier to simulate event on PublishSubject as all you have to do is:</p><pre>let somePublishSubject = PublishSubject&lt;Bool&gt;()<br>somePublishSubject.onNext(true)</pre><p>Also, this allows us to just bind events from the View Controller to View Model, and we are still using Observables in View Model for events that View Controller can subscribe on.</p><h3>Example</h3><p>Let’s pretend we have a View Controller that shows one label with counter value and one button to increase that value. View Model is responsible for handling each tap, increasing the counter and letting View Controller know that label should be updated and what it should be updated with. Also, we are going to write unit tests for both, and integration test to make sure these two together are working as they should.</p><p>Download <a href="https://github.com/arasmarko/testing-mvvm-rx">example repo</a> and check it out so you can follow along easier.</p><p><em>testIncreaseButtonTaps_WithOneTapEvent_LabelTextShouldBeOne </em>method in <em>CounterViewModelTests </em>is the best example of simulating events from View Controller<em>.</em></p><pre>func testIncreaseButtonTaps_WithOneTapEvent_LabelTextShouldBeOne() {</pre><pre>    let observer: TestableObserver&lt;String&gt; = scheduler.createObserver(String.self)</pre><pre>    let correctResult: [Recorded&lt;Event&lt;String&gt;&gt;] = [next(0, &quot;0&quot;), next(1, &quot;1&quot;)]</pre><pre>    sut.counterValue<br>        .subscribe(observer)<br>        .disposed(by: disposeBag)</pre><pre>    let allEvents = scheduler.createHotObservable([next(1, ())])</pre><pre>    allEvents<br>        .bind(to: sut.increaseButtonTaps)<br>        .disposed(by: disposeBag)</pre><pre>    scheduler.start()<br>    XCTAssertEqual(correctResult, observer.events)</pre><pre>}</pre><p>Here we are creating <em>TestableObserver </em>that we are going to use to compare with some result of type <em>[Recorded&lt;Event&lt;String&gt;&gt;]. </em>Next thing we have to do is simulate some events, and we have to do it at exact time.</p><p>As you can see, we are simulating a new tap event at timestamp 1. The expected result is the label to have text “0” at the start and text “1” after the simulated tap. Run tests and check if everything is passing.</p><p>Check out <em>CounterViewControllerTests </em>to see how easy it is to inject <em>Mock </em>of a View Model.</p><p>Also look at integration tests for this screen to see the way I implemented it.</p><p>Thank you for your attention and please let me know if you have a better solution for anything above.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2f99ededea63" width="1" height="1" alt=""><hr><p><a href="https://medium.com/arasdigitalproducts/testing-mvvm-with-rxswift-code-2f99ededea63">Testing MVVM with RxSwift code</a> was originally published in <a href="https://medium.com/arasdigitalproducts">Aras™ Digital Products</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>