<?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 Aaron Sutula on Medium]]></title>
        <description><![CDATA[Stories by Aaron Sutula on Medium]]></description>
        <link>https://medium.com/@asutula?source=rss-debfdff4580c------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*POmSons4uZCeoI-HA2dR6Q.jpeg</url>
            <title>Stories by Aaron Sutula on Medium</title>
            <link>https://medium.com/@asutula?source=rss-debfdff4580c------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 18:48:42 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@asutula/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[Introducing the Textile Android SDK]]></title>
            <link>https://medium.com/textileio/introducing-the-textile-android-sdk-dd20eca0c19a?source=rss-debfdff4580c------2</link>
            <guid isPermaLink="false">https://medium.com/p/dd20eca0c19a</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[sdk]]></category>
            <category><![CDATA[textile]]></category>
            <category><![CDATA[ipfs]]></category>
            <category><![CDATA[mobile]]></category>
            <dc:creator><![CDATA[Aaron Sutula]]></dc:creator>
            <pubDate>Mon, 10 Jun 2019 17:34:38 GMT</pubDate>
            <atom:updated>2019-06-10T17:34:38.775Z</atom:updated>
            <content:encoded><![CDATA[<h4>The easiest way to run Textile and IPFS in your native app</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-XWuECqr80I3jwEY" /><figcaption>Photo by <a href="https://unsplash.com/@rami_alzayat?utm_source=medium&amp;utm_medium=referral">Rami Al-zayat</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>One of our goals at Textile is to make it as easy as possible to build distributed applications on <a href="https://textile.io/">Textile</a> and <a href="https://ipfs.io/">IPFS</a> technology. We’re making more and more progress on that goal every day.</p><p>Today we’re excited to release the first version of the Textile SDK for Android. Like our <a href="https://medium.com/textileio/introducing-the-textile-sdk-for-ios-e180e5c16461">recent iOS release</a>, the Andriod SDK expands the number of platforms available for Textile development. This is exciting because it allows Textile-enabled Android apps to not only communicate with each other, but to communicate with Textile-enabled apps on any of our supported platforms (already linux, macOS, Windows, iOS, and desktop web!).</p><p>As with all Textile libraries, the Android SDK enables apps to run Textile and IPFS peers natively (directly on mobile devices in this case), leverage easy to use distributed databases called Threads, and call APIs that make encryption, storage, and sharing of data over IPFS easy and secure.</p><p>Let’s take a look at a couple quick examples.</p><h4>Create a Thread, Textile’s distributed database:</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bcad73182f6b9acefe247c8ccb7d6c94/href">https://medium.com/media/bcad73182f6b9acefe247c8ccb7d6c94/href</a></iframe><p>This Thread can now be used to share media, messages, and annotations with any other Textile user that is participating in the Thread.</p><h4>Invite another Textile user to a Thread:</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/037d81e9479e0bc821dd89e0bf6ff5c5/href">https://medium.com/media/037d81e9479e0bc821dd89e0bf6ff5c5/href</a></iframe><p>The Contact you added to the Thread will receive an invitation and can now view the contents of, and share data to, the Thread.</p><p>We’re super excited to see what Android apps can be built with the new SDK, and we have plans to keep improving and expanding it’s capabilities. Star or watch the <a href="https://github.com/textileio/android-textile/">GitHub repo</a> and <a href="https://docs.textile.io/">check out the docs</a> to learn more about how to build resilient, decentralized Android apps.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dd20eca0c19a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/textileio/introducing-the-textile-android-sdk-dd20eca0c19a">Introducing the Textile Android SDK</a> was originally published in <a href="https://medium.com/textileio">Textile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing the Textile SDK for iOS]]></title>
            <link>https://medium.com/textileio/introducing-the-textile-sdk-for-ios-e180e5c16461?source=rss-debfdff4580c------2</link>
            <guid isPermaLink="false">https://medium.com/p/e180e5c16461</guid>
            <category><![CDATA[ipfs]]></category>
            <category><![CDATA[mobile]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[decentralization]]></category>
            <dc:creator><![CDATA[Aaron Sutula]]></dc:creator>
            <pubDate>Tue, 28 May 2019 17:10:13 GMT</pubDate>
            <atom:updated>2019-05-28T17:10:13.815Z</atom:updated>
            <content:encoded><![CDATA[<h4>Native mobile access to the decentralized web for super-charging your mobile dApps</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rOUGrtoRZlhpu0GQ" /><figcaption>Photo by <a href="https://unsplash.com/@grohsfabian?utm_source=medium&amp;utm_medium=referral">Fabian Grohs</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Any good cross-platform SDK needs a good iOS library, or two! Today, we are happy to announce the release of the <a href="https://docs.textile.io/develop/clients/ios/">Textile SDK for iOS</a>, enabling anyone who’s developing mobile apps in Swift or Objective-C to easily incorporate Textile and all the goodies it contains.</p><h4>What can you do with the new SDK?</h4><p>While we’ve previously released our <a href="https://docs.textile.io/develop/clients/javascript/">JavaScript</a> and <a href="https://docs.textile.io/develop/clients/react-native/">React Native SDKs</a>, we’ve had a lot of people asking for the native-only API. With this new release, your browser, desktop, or even smart contract based app can have an iOS app too. Your app can use the libp2p, IPFS, and Textile stack (it’s LIT!) to help you deliver unstoppable applications:</p><p>Use Textile <a href="https://docs.textile.io/concepts/threads/">threads</a> to deploy and synchronize a decentralized database in your mobile app, use <a href="https://ipfs.io/">IPFS</a> to store and transfer any type of data, leverage end-to-end encrypted communication via <a href="https://libp2p.io/">libp2p</a>, and offer your users new ways to access and control the data your app creates.</p><p>Here’s a look at what the iOS SDK could mean for your app.</p><h4>Connect anyone, anywhere</h4><p>Threads provide flexible data sharing and synchronization for mobile and desktop applications. Your app can create private, encrypted spaces for your users to share photos, host a conversation, or exchange private documents. They extend the core IPFS stack to help you build applications that can connect anyone, anywhere in the world.</p><h4>Build resilient applications</h4><p>The IPFS network provides a backbone to run applications that are resistant to tampering, censoring, or throttling. You can now tap into those benefits through the Textile SDK for iOS. Textile configures a local IPFS peer to work well for the mobile constraints of connectivity, frequent life-cycles, and battery needs.</p><h4>Any platform, the same decentralized interface</h4><p>The native iOS library is joining a growing family of Textile tools to support cross-platform applications; React Native, JavaScript, and Go support is already available, and the beta release of Android is right behind them. We want it to be easy and consistent no matter how you want to get your app to your users, so we’re focused on making these libraries complimentary and unified. Hopefully, you’ll enjoy using them!</p><h4>Getting started</h4><p>We’ve added Swift and Objective-C examples to our <a href="https://docs.textile.io/a-tour-of-textile/">Tour of Textile</a>, so that’s a great place to start. Additionally, the <a href="https://docs.textile.io/develop/clients/ios/">iOS portion</a> of our docs gives a good overview of some of the basic APIs to help get you started.</p><h4>Let’s look at a Swift example</h4><p>Let’s subscribe to real-time updates of a <a href="https://docs.textile.io/concepts/threads/">thread</a>, the decentralized databases that power Textile.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/06affcf06e760b4f60494607efa9e1bc/href">https://medium.com/media/06affcf06e760b4f60494607efa9e1bc/href</a></iframe><p>Simple as that. Next, let’s encrypt a file, add it to IPFS and share it back to our thread.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2463b71d1eb834c2ac5ac7342effb5a2/href">https://medium.com/media/2463b71d1eb834c2ac5ac7342effb5a2/href</a></iframe><p>Interested? Come join our <a href="https://slack.textile.io/">developer Slack channel</a> if you want to learn from and share with the community!</p><p>Finally, if you are going to be in <a href="http://altconf.com/">San Jose for AltConf</a>, come meet us there! We’ll be giving a talk about running IPFS on mobile devices. We’d love to meet you.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e180e5c16461" width="1" height="1" alt=""><hr><p><a href="https://medium.com/textileio/introducing-the-textile-sdk-for-ios-e180e5c16461">Introducing the Textile SDK for iOS</a> was originally published in <a href="https://medium.com/textileio">Textile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Recipe For Building a Closed Source Swift Framework With Dependencies]]></title>
            <link>https://medium.com/textileio/recipe-for-building-a-closed-source-swift-framework-with-dependencies-dea3109ebd21?source=rss-debfdff4580c------2</link>
            <guid isPermaLink="false">https://medium.com/p/dea3109ebd21</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Aaron Sutula]]></dc:creator>
            <pubDate>Thu, 07 Sep 2017 13:47:36 GMT</pubDate>
            <atom:updated>2017-09-07T13:47:36.609Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="http://www.bensnider.com/abi-compatibility-whoopdty-do-what-does-it-all-mean.html">ABI compatibility issues</a> aside, sometimes you may want to distribute a binary version of your Swift framework. This framework should be a ‘fat’ framework (supporting both simulator and iOS device architectures), and may depend on other third party frameworks. There is no Xcode project template for this, but you’ll find helpful information on the Internet. It basically comes down to using xcodebuild to create two versions of your framework, one for the simulator and one for real iOS devices, and then using the lipo command to combine them into a single fat framework.</p><p>It seems pretty straight forward, but after following instructions found online (examples <a href="https://eladnava.com/publish-a-universal-binary-ios-framework-in-swift-using-cocoapods/">here</a>, <a href="https://medium.com/wireless-registry-engineering/create-a-universal-fat-swift-framework-b7409bbfa18f">here</a>, and <a href="https://gist.github.com/eladnava/0824d08da8f99419ef2c7b7fb6d4cc78">here</a>), we experienced runtime crashes when using the binary version of our framework in an app. The crash would happen when our framework, called MyFramework in the following example, would try to use a symbol from any third party framework dependency. The crash would look like this when MyFramework tried to use RxSwift&#39;s ObservableType:</p><pre>dyld: lazy symbol binding failed: Symbol not found: __TIFE7RxSwiftPS_14ObservableType9subscribeFT6onNextGSqFwx1ET__7onErrorGSqFPs5Error_T__11onCompletedGSqFT_T__10onDisposedGSqFT_T___PS_10Disposable_A0_</pre><pre>Referenced from: /Users/aaron/Library/Developer/CoreSimulator/Devices/335F6B8A-0CBC-406D-9559–5718D4910F5A/data/Containers/Bundle/Application/47AA11E3-C2E5–4FCB-A86C-36092990EF0E/Consumer.app/Frameworks/MyFramework.framework/MyFramework</pre><pre>Expected in: /Users/aaron/Library/Developer/CoreSimulator/Devices/335F6B8A-0CBC-406D-9559–5718D4910F5A/data/Containers/Bundle/Application/47AA11E3-C2E5–4FCB-A86C-36092990EF0E/Consumer.app/Frameworks/RxSwift.framework/RxSwift</pre><p>After lots of investigation and experimention, we found a process that produces a fat framework that is crash-free when referencing symbols from other third party frameworks. It’s one of those things where I can’t totally explain what the problem was or why this works, but I wanted to share it here:</p><h4>Create your framework</h4><p>Use the Cocoa Touch Framework Xcode template, and feel free to depend on other frameworks however you choose (Cocoapods, Carthage, drag n’ drop, etc).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J7cqAz_Inxsxgr5dEOoDRw.png" /></figure><h4>Create a target to build the fat framework</h4><p>Use the Aggregate target type in the Cross-platform section. This creates a minimal target we can add a single run script build phase to. I’ll call this target BuildFatFramework.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1ujAJwQh_v_ZeigFRyhE5g.png" /></figure><h4>Add the fat framework building shell script to the target</h4><p>Add a run script build phase to the BuildFatFramework target, and add the following shell script to it:</p><pre># 1<br># Set bash script to exit immediately if any commands fail.</pre><pre>set -e</pre><pre># 2<br># Setup some constants for use later on.</pre><pre>FRAMEWORK_NAME=&quot;MyFramework&quot;<br>OUTPUT_DIR=&quot;${SRCROOT}/build&quot;</pre><pre># 3<br># If remnants from a previous build exist, delete them.</pre><pre>if [ -d &quot;${OUTPUT_DIR}&quot; ]; then<br>rm -rf &quot;${OUTPUT_DIR}&quot;<br>fi</pre><pre># 4<br># Build the framework for device and for simulator (using<br># all needed architectures).</pre><pre>xcodebuild -workspace &quot;${FRAMEWORK_NAME}.xcworkspace&quot; -scheme &quot;${FRAMEWORK_NAME}&quot; -configuration Release -arch arm64 -arch armv7 -arch armv7s only_active_arch=no defines_module=yes -sdk &quot;iphoneos&quot; -derivedDataPath &quot;${OUTPUT_DIR}&quot;</pre><pre>xcodebuild -workspace &quot;${FRAMEWORK_NAME}.xcworkspace&quot; -scheme &quot;${FRAMEWORK_NAME}&quot; -configuration Release -arch x86_64 -arch i386 only_active_arch=no defines_module=yes -sdk &quot;iphonesimulator&quot; -derivedDataPath &quot;${OUTPUT_DIR}&quot;</pre><pre># 5<br># Remove .framework file if exists from previous run.</pre><pre>if [ -d &quot;${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework&quot; ]; then<br>rm -rf &quot;${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework&quot;<br>fi</pre><pre># 6<br># Copy the device version of framework.</pre><pre>cp -r &quot;${OUTPUT_DIR}/Build/Products/Release-iphoneos/${FRAMEWORK_NAME}.framework&quot; &quot;${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework&quot;</pre><pre># 7<br># Replace the framework executable within the framework with<br># a new version created by merging the device and simulator<br># frameworks&#39; executables with lipo.</pre><pre>lipo -create -output &quot;${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}&quot; &quot;${OUTPUT_DIR}/Build/Products/Release-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}&quot; &quot;${OUTPUT_DIR}/Build/Products/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}&quot;</pre><pre># 8<br># Copy the Swift module mappings for the simulator into the<br># framework. The device mappings already exist from step 6.</pre><pre>cp -r &quot;${OUTPUT_DIR}/Build/Products/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/&quot; &quot;${OUTPUT_DIR}/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule&quot;</pre><p>Customize this script as needed to fit your project.</p><h4>Initiate the build from the BuildFatFramework target</h4><p>Now you can build your fat framework by running the BuildFatFramework target of your Xcode project.</p><p><strong>Very important: </strong>If buiding from the command line, be sure to use xcodebuild, specifying BuildFatFramework as the scheme and build as the action (not archive which is the default if you don’t specify an action). <strong>This was the key step that led to our crash-free framwork</strong>.</p><p>The archive action is not correct, and additionaly, it seems like Xcode is doing something to properly set up the build environment when you build the BuildFatFramework scheme. Saving the contents of the shell script that builds the fat framework to a stand alone file, and running it directly, bypassing the BuildFatFramework scheme, resulted in a framework that crashed.</p><p>Here is the command we use in our CI system to initiate the building of the fat framework:</p><pre>xcodebuild -scheme BuildFatFramework -workspace MyFramework.xcworkspace build</pre><p>Hopefully Xcode will provide better support for building fat frameworks in the future, but until then, I hope this information can be useful to someone out there.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dea3109ebd21" width="1" height="1" alt=""><hr><p><a href="https://medium.com/textileio/recipe-for-building-a-closed-source-swift-framework-with-dependencies-dea3109ebd21">Recipe For Building a Closed Source Swift Framework With Dependencies</a> was originally published in <a href="https://medium.com/textileio">Textile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Your First Set App Using MVVM and RxSwift]]></title>
            <link>https://medium.com/textileio/build-your-first-set-app-using-mvvm-and-rxswift-5a37d027950f?source=rss-debfdff4580c------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a37d027950f</guid>
            <category><![CDATA[mvvm]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[rxswift]]></category>
            <category><![CDATA[setsdk]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Aaron Sutula]]></dc:creator>
            <pubDate>Tue, 04 Apr 2017 14:59:20 GMT</pubDate>
            <atom:updated>2017-04-04T14:59:20.400Z</atom:updated>
            <content:encoded><![CDATA[<p><strong><em>Summary:</em></strong><em> In this post we’ll walk through building your first Set app in four parts. Part I will introduce you to the MVVM app architecture. Part II will demonstrate the SetSDK setup procedure. Part III will apply MVVM concepts to creating the scaffolding for your app. Finally, in Part IV we’ll use the SetSDK to display departure and predicted destination in real-time throughout the day.</em></p><p>The source code for this project can be downloaded from the <a href="https://gitlab.com/weareset/MVVM-SetSDK">Set Gitlab repo</a>.</p><p>The <a href="https://www.set.gl/">Set SDK</a> allows any developer to integrate machine learning and user behavior forecasting into their own applications with a simple a pod install. The <a href="https://cocoapods.org/pods/SetSDK">first SDK release</a> focuses on user location, answering the questions: Where are they now and where will they go next?</p><p>I want to provide a simple demo application that shows how to integrate the SDK into your own project and use some of the SDK’s functionality. While I’m at it, I’ll do it using an alternative to Apple’s MVC (Model View Controller) architecture, MVVM (Model View View Model), and one technology that enables MVVM called <a href="https://github.com/ReactiveX/RxSwift/">RxSwift</a>.</p><h3>Part I. MVVM Overview</h3><p>There’s plenty of information out there about why the MVC design pattern becomes a headache, especially in more complex applications. MVC puts too much responsibility on the view controller. There’s very little separation of concerns. In the following diagram, you see the view and model mainly just exist without doing much of anything, while the view controller is responsible for updating and receiving updates from both the model and view as well as any business logic, database access, networking and more.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wYpwhhjepl8ubum9zTFKFA.png" /><figcaption>MVC architecture, image via Wikipedia (<a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller</a>)</figcaption></figure><p>In a complex application, a view controller can grow to be thousands of lines of code, and very hard to maintain.</p><p>MVVM is a simple addition to MVC and simplifies the role of the view controller:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/533/1*4vRW7TDlTwXPbviQVbvc-g.png" /><figcaption>MVVM architecture, image via <a href="http://khanlou.com/2014/03/model-view-whatever/">http://khanlou.com/2014/03/model-view-whatever/</a></figcaption></figure><p>For each screen or view controller in your app, we introduce one additional file, the view model. The <strong>view model is responsible for interacting with model data, and applying business logic and display formatting</strong> to that data. The view model may also utilize database or network abstractions. The formatted data is made available to the view layer of your app, usually through simple properties, RxSwift Observables or a similar technology (more on that later).</p><p>The new role of the view controller is to simply ‘bind’ the data exposed by the view model to the view, usually using tools provided by something like RxSwift. The view controller also handles user interactions like button taps and gestures, notifying the view model of those events. In this way, the view and view model are tightly coupled and can be considered a single functional unit.</p><p>MVVM creates a more clear separation of concerns. It removes business logic and data formatting from the view layer and creates view models that are easily tested with unit tests. Much of the app can be tested in a ‘headless’ manner (without any views) while the views can be tested using more suitable tools like Xcode UI tests. This results in an app with fewer bugs that is more easily maintained.</p><h3>Part II. Starting a SetSDK App</h3><p>To launch the SetSDK, you’ll need client credentials for your app. We’re currently working on a self-service developer portal where you’ll be able to create these credentials, but for now email <a href="/service/mailto:sander@set.gl">sander@set.gl</a> and you’ll receive your credentials via email.</p><p>The SetSDK is distributed using <a href="https://cocoapods.org/">Cocoapods</a>. If you’re unfamiliar with it, check out their <a href="https://cocoapods.org/">website</a> with plenty of <a href="https://guides.cocoapods.org/">great documentation</a> about how to get started.</p><p>Create a new Xcode project using File &gt; New &gt; Project… &gt; Single View Application. I’m calling mine MVVMSetSDK. Once the project is created, close it and navigate to the root directory of the project on the command line.</p><p>Initialize Cocoapods by running pod init. Open the newly created Podfile for editing and add the SetSDK dependency to it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e77cb12bacb8da450afb30e3c4611e41/href">https://medium.com/media/e77cb12bacb8da450afb30e3c4611e41/href</a></iframe><p>Close the Podfile and run pod install. Cocoapods will create a Xcode workspace, called MVVMSetSDK.xcworkspace in my case, and install SetSDK and it’s dependencies. Open the newly created workspace in Xcode, and let’s get to building our app.</p><p>As described in the <a href="https://docs.set.gl/getting-started/run-the-sdk.html">SetSDK documentation</a>, we need to enable the Location updates Background Mode,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AVJryxqRiqSymFyboaMpIw.png" /><figcaption>Enabling the Location updates background mode, required to use SetSDK</figcaption></figure><p>and provide Info.plist strings that are displayed to the user when we ask to use their location and motion data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qPM3PlaG4I_Ca1YjCIx5rQ.png" /><figcaption>Providing Location Always and Motion Usage Info.plist strings. In a real app, these should be more descriptive.</figcaption></figure><h3>Part III. MVVM Scaffolding</h3><h4>Basic Design</h4><p>The design of our app will dictate the types of view controllers and view models we create, and will determine how those view models communicate with each other. For this app, our root view controller will be a UINavigationController. This navigation controller’s view model will be responsible for creating child view models that correspond to child view controllers that will be pushed onto the navigation stack. We’ll have two child view controllers, one for user login and one for displaying some data from the SetSDK after the user is logged in:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QxKYscaWiTquv3b6NfbymA.jpeg" /></figure><h4>Creating the Root View Controller and View Model</h4><p>Start by opening Main.storyboard and deleting the automatically created view controller you see in there. Next, drag in a UINavigationController and give it a Storyboard ID of rootViewController. You can delete the automatically created UITableViewController that is set as the navigation controller’s root view controller. We’ll be creating our own soon. Your storyboard should look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aJH6cRazgdJgNHr7OXlMOg.png" /></figure><p>Next, create two new Swift files in your app, RootViewModel.swift:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/30820dbd627d91ab57b5e2890dc791d4/href">https://medium.com/media/30820dbd627d91ab57b5e2890dc791d4/href</a></iframe><p>and RootViewController.swift:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fbff29035acc3453cb29e03340f1fd6d/href">https://medium.com/media/fbff29035acc3453cb29e03340f1fd6d/href</a></iframe><p>Make sure RootViewController is a subclass of UINavigationController. We’ll add a property to reference the view model. In MVVM, <strong>view controllers always own their view models, and view models know nothing about view controllers</strong>. We’ll make sure our viewModel property is set next.</p><p>Go ahead and set the Custom Class of the UINavigationController in our storyboard to RootViewController.</p><h4>View Controller Creation</h4><p>Our style of <strong>MVVM relies on having an easy way to create the appropriate view controller for a given view model</strong>. For a simple app like this, we’ll create a Swift file called Globals.swift that contains a function that creates the correct view controller for the provided view model, sets the viewModel property of the view controller to the provided view model instance, and then returns the view controller:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/66966aa76512d9bfc0f34cfa0c8aee4a/href">https://medium.com/media/66966aa76512d9bfc0f34cfa0c8aee4a/href</a></iframe><p>We’ll add additional switch cases to this function as we add more view models and view controllers to our app. For a more complex app, you’ll want to come up with a better way of maintaining this mapping between view models and view controllers, perhaps using a factory pattern or protocol.</p><p>Let’s update our AppDelegate to create and set our app’s root view controller based on our RootViewModel:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b9c33b068b0a84bd7b743b5af5e686b5/href">https://medium.com/media/b9c33b068b0a84bd7b743b5af5e686b5/href</a></iframe><p>Above, we’re manually creating our AppDelegate’s window, and setting it’s rootViewController using our global function that maps our view model to a view controller.</p><h4>Navigation as Business Logic</h4><blockquote>View controllers and views should be ‘dumb’; they know nothing about how they’re presented and dismissed, and they don’t know what screen was presented previously or which screen should be presented next.</blockquote><p>One important concept in the flavor of MVVM we use at Set is that <strong>app navigation is related to business logic and should be handled by the view model layer</strong>. In that scenario, view controllers and views should be ‘dumb’; they know nothing about how they’re presented and dismissed, and they don’t know what screen was presented previously or which screen should be presented next. View models keep track of that and make navigation decisions based on the business logic and data they contain.</p><p>We’ll add some code to our RootViewModel and RootViewController to achieve this.</p><p>RootViewModel:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5f833cb8bfd2dfd14dc7c782d3ce9626/href">https://medium.com/media/5f833cb8bfd2dfd14dc7c782d3ce9626/href</a></iframe><p>RootViewController:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a6dae9c75325a5c57f8761d5bcc0f9a8/href">https://medium.com/media/a6dae9c75325a5c57f8761d5bcc0f9a8/href</a></iframe><p>We’ve introduced a couple RxSwift concepts here and are seeing our first use of data binding between view controller and view model.</p><h4>Observable</h4><p>The first thing to understand is RxSwift’s Observable class. An Observable represents a series of strongly typed values that occur over time. This series of values can be transformed with functional operators like map, flatMap, filter, and many more. Code that is interested in the values being delivered by an Observable can use the Observable.subscribe() function to receive values as they occur, or can use one of the many RxCocoa (an extension to RxSwift for UIKit binding) operators to bind an Observables directly to UIKit views. There’s so much to know about Observables so head over to the <a href="https://github.com/ReactiveX/RxSwift#i-came-here-because-i-want-to-">RxSwift documentation</a> to learn more.</p><h4>Modeling Navigation in the View Model</h4><p>In RootViewModel, we created the enum NavigationStackAction that represents the different navigation actions we may want to apply to a UINavigationController(RootViewContoller in our case). Then we added a BehaviorSubject property to the view model that will expose a series of NavigationStackActions to RootViewController. BehaviorSubject is an extension of Observable that allows you to programmatically send values using BehaviorSubject.onNext(element:). It also has the convenient behavior of delivering the last (or current) value to any new subscribers. For now, the BehaviorSubject is initialized with a .set NavigationStackAction containing an empty array of view models.</p><h4>Binding to the View Model’s Navigation Data</h4><p>In RootViewController, we override viewDidLoad() and subscribe (bind) the view controller to the view model’s BehaviorSubject of NavigationStackActions. Within the subscription closure, we examine the type of NavigationStackAction and modify the navigation stack appropriately. Notice our global function to map view models to view controllers is used to create the view controllers that are added to the navigation stack.</p><p><strong>Important note:</strong> To prevent retain cycles and assure that subscriptions are disposed of upon deallocation of RootViewController, we added [weak self] to our subscription closure’s capture list and added the Disposable returned by Observable.subscribe() to a DisposeBag that is stored as an instance property of our view controller. Like I said, lots to learn. See the <a href="https://github.com/ReactiveX/RxSwift/blob/master/Documentation/GettingStarted.md#disposing">documentation here</a>.</p><p>We’re now in a position where we can control app navigation from the business logic contained in RootViewModel. Now let’s create some view model/view controller pairs to navigate to.</p><h4>Creating the Login Screen</h4><p>We’ll keep the login screen very simple. It should contain a text field for the user to input their 11 digit phone number, and a button to submit the form. We’ll verify it’s a 11 digit number and then use it as our user id to launch the SetSDK. In a real application, you’d obviously want to use actual authentication to identify your users.</p><p>Let’s start by creating the view controller in Main.storyboard and give it a Storyboard ID of loginViewController:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Mu12AMpupoRLRHnWrh7itA.png" /></figure><p>Next, we’ll create two new Swift files for LoginViewModel:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a95b47721ed3f0f62d2d1df267a8db8c/href">https://medium.com/media/a95b47721ed3f0f62d2d1df267a8db8c/href</a></iframe><p>and LoginViewController:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bc5a56f0d6744de57be8d5df6463ecfd/href">https://medium.com/media/bc5a56f0d6744de57be8d5df6463ecfd/href</a></iframe><p>Be sure to set the Custom Class of the login view controller you created in Main.storyboard to LoginViewController and wire up the @IBOutlets.</p><p>Let’s add the appropriate switch case to our global viewController(forViewModel:) function:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/79939d6702f88f0460e80e4377e6d2e4/href">https://medium.com/media/79939d6702f88f0460e80e4377e6d2e4/href</a></iframe><p>UpdateRootViewModel by initializing our navigation stack with the login view model:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c7ea7ca0399c7363149c7b9e8b2ac9e1/href">https://medium.com/media/c7ea7ca0399c7363149c7b9e8b2ac9e1/href</a></iframe><p>Another important concept in the style of MVVM we use at Set is that <strong>view models create and manage other ‘child’ view models</strong>, mirroring the parent/child relationship between nested view controllers in an app. <strong>Parent view models can observe or query the child view models they create, but child view models know nothing of their parent.</strong> In the code above, RootViewModel is the parent and LoginViewModel is the child.</p><p>Run the app now, and you should see the login screen appear:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/487/1*jb6A7KwQy5aod5lm004ETQ.png" /></figure><p>Let’s add some behavior to the login screen. I want the Submit button to be disabled until the user has entered an 11 digit phone number. When the submit button is tapped, we’re going to fake a real authentication process, and notify the RootViewModel that the user has successfully logged in.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fb1e0fdf0d57a27a27adc0eda87eea70/href">https://medium.com/media/fb1e0fdf0d57a27a27adc0eda87eea70/href</a></iframe><p>Let’s walk through the above LoginViewModel code.</p><p>First, we use a RxSwift Variable to keep track of the phone number entered by the user. Variables represent a value that can change over time. You can ask for the current value, or convert the Variable to an Observable to subscribe to changes.</p><p>Then we created an Observable called phoneNumberIsValid that will send false until the phone number is exactly 11 digits long. This is done by converting the phoneNumber Variable to an Observable and mapping it to true or false depending on if the phone number matches a regular expression.</p><p>Lastly, we create a simple submit() function that will be called when the user taps the Submit button. It doesn’t do anything yet, but we’ll get to that soon.</p><p>Next, we’ll modify LoginViewController and bind it to LoginViewModel.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9e8dfbf439ff459abea0b2816912f454/href">https://medium.com/media/9e8dfbf439ff459abea0b2816912f454/href</a></iframe><p>Here we used RxCocoa’s UIKit bindings to bind the text field’s current text to the view model’s phoneNumber Variable. As the user enters new text, the phoneNumber Variable is updated in real time.</p><p>We bind the isEnabled property of our button to the view model’s phoneNumberIsValid Observable so the user can only tap the submit button when there is a valid phone number entered.</p><p>Lastly, we bind button taps to the view model’s submit() function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/302/1*Pl89bkn2_KZ89gl4O7oZCw.gif" /></figure><p>Even in this oversimplified example, you can see the benefits of MVVM and RxSwift. Our code is clean and concise. There is good separation of view and business logic. We’ve added fairly sophisticated behavior to our view controller with just a few lines of declarative code, and we did all this with none of the delegate, target action, or NSNotification patterns we usually see in iOS.</p><h4>Communicating With the Parent View Model</h4><p>Sometimes certain user actions or events will be handled in the view model that initially receives them. Other times, we may want to handle an event or action in some other view model higher up the view model hierarchy. As I mentioned before, a view model should know nothing about it’s parent view model, so how do we achieve this?</p><p>One solution is to create a PublishSubject on the child view model (PublishSubject is similar to the BehaviorSubject we used earlier, but doesn’t send the most recent value to new subscribers). The code in that child view model can simply send a data representation of the event or action that occurred by calling PublishSubject.onNext(element:). At the time the parent view model creates the child view model, the parent can subscribe to the child’s event PublishSubject and then respond appropriately as events are received.</p><h3>Part IV. Using SetSDK</h3><h4>Handling Login and Launching SetSDK</h4><p>I want the launching of the SetSDK to be handled in the RootViewModel, so the LoginViewModel doesn’t need to handle the login event, but we do need to let RootViewModel know about it.</p><p>Let’s modify LoginViewModel to send an event when the user successfully logs in by submitting their phone number:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/76ee502151239c340df832f0b33406fe/href">https://medium.com/media/76ee502151239c340df832f0b33406fe/href</a></iframe><p>I’m just showing the additions here. We created an enum LoginViewModel.Event to represent the events that occur, in this case, the user successfully logging in. We created the events PublishSubject that the parent view model can subscribe to, and the submit() function now sends the .loggedIn event through the events PublishSubject.</p><p>Let’s update RootViewModel to handle that event and launch SetSDK:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c9e417e8018ac142bea7ae2dee04bd27/href">https://medium.com/media/c9e417e8018ac142bea7ae2dee04bd27/href</a></iframe><p>Be sure to set your Set client id and secret.</p><p>We refactored the creation of the LoginViewModel, wrapping it in a function were we create it and then subscribe to it’s Observable of LoginViewModel.Events before returning it. When a .loggedIn event is received, a private function is called to launch the SetSDK.</p><h4>Using Our MVVM Tools</h4><p>You’ve now seen the basics of how we use MVVM at Set.</p><p>We’ve covered MVVM architecture, navigation in the view model layer, creating specific view controllers for specific view models, binding view controllers to view models using RxSwift, and bubbling events from child view models up to parent view models, and responding to those events.</p><p>Once the SetSDK is launched, we now have the tools to create and navigate to a new screen that will display some output from SetSDK. Let’s create new files for SetViewModel and SetViewController(as well as it’s storyboard representation), and handle them in the Globals.swift view controller factory function. In RootViewModel, we’ll trigger the presentation of that screen in the SetSDK.launch() completion handler and handle a .logOut event from the SetViewModel as you can see in RootViewModel here:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/414b2932aea80cf86b6629ae846689d3/href">https://medium.com/media/414b2932aea80cf86b6629ae846689d3/href</a></iframe><h4>Using SetSDK’s Functions</h4><p>The SetViewModel will use two SetSDK functions. We’ll use <a href="https://docs.set.gl/api-reference/methods.html#ondeparture">SetSDK.onDeparture(from:eventHandler:)</a> to receive a callback from the SDK whenever the user leaves a known place. Within the callback closure of that function, we’ll call <a href="https://docs.set.gl/api-reference/methods.html#getdestination">SetSDK.getDestination(fromLocation:fromTimestamp:)</a> to find out where the user is likely going next.</p><p>In SetViewModel, we’ll wrap the SetSDK function calls in RxSwift Observables to make it easy to bind the data to the UI. You’ll see it’s very easy to derive new Observables from existing Observables in order to create and expose additional data to the SetViewController.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/424243281b3bd841f475e407a31b6507/href">https://medium.com/media/424243281b3bd841f475e407a31b6507/href</a></iframe><p>We’ve created Observables to model the departure time, departure place name, arrival time, destination place name, and destination place location, as well as created a function to handle log out. Next, let’s bind the views of SetViewController to SetViewModel:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b65f73bd7dff0d2827fcccf0327f01c7/href">https://medium.com/media/b65f73bd7dff0d2827fcccf0327f01c7/href</a></iframe><p>With all that in place, the SetSDK screen will display departure and arrival information from SetSDK and update in real time as additional departure callbacks are received from SetSDK.onDeparture(from:eventHandler:). The user can log out and return to the log in screen by tapping the Log Out button:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/487/1*FCb88cpOzWy9DkSrkiBU2A.png" /></figure><h3>Looking Forward</h3><p>It’s an exciting time at Set. We see a lot of potential to share some of the tools we’re working on, including a more structured version of the MVVM concepts I covered in this post. We’re moving quickly on adding new features and behavior forecasting APIs to our SDK. If you’re interested in experimenting with the SDK, please <a href="https://www.set.gl/">sign up</a> for developer access and keep an eye on our <a href="https://blog.set.gl/">blog</a> for updates.</p><p>I hope you’ve learned some ways to improve your own apps by using MVVM, and that I’ve sparked some ideas about the powerful things you can do by adding SetSDK’s user behavior forecasts to your own apps. Thanks for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a37d027950f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/textileio/build-your-first-set-app-using-mvvm-and-rxswift-5a37d027950f">Build Your First Set App Using MVVM and RxSwift</a> was originally published in <a href="https://medium.com/textileio">Textile</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>