tag:fbernardo.org,2014:/feedFábio Bernardo2016-05-19T10:00:46-07:00Fábio Bernardohttps://fbernardo.orgSvbtle.comtag:fbernardo.org,2014:Post/server-side-swift-notes2016-05-19T10:00:46-07:002016-05-19T10:00:46-07:00Server-side Swift notes<blockquote>
<p>This is the result of a recent look into server-side Swift for my own personal use. This area is changing everyday, and with less than a month until WWDC, expect most of this to become incorrect in the future.</p>
</blockquote>
<hr>
<p>It all started with me researching the Amazon Alexa Skills SDK: apparently those are just calls to a previously defined Web Service with a predefined list of commands. And since I live outside the US testing Alexa is tricky, so I decided to try my idea with something similar: Slack’s slash commands.</p>
<p>I’ve heard that Swift on the server isn’t for <em>serious</em> projects so this was a perfect fit. With that in mind I followed <a href="http://www.bensnider.com/making-a-slack-slash-command-integration-using-swift-on-heroku.html">Ben Snider’s tutorial</a> (thank you) and quickly discovered that this wasn’t exactly the Swift I was used to.</p>
<p>The following is a list of caveats, problems or notes produced during this short project.</p>
<h1 id="managing-swift-versions_1">Managing Swift versions <a class="head_anchor" href="#managing-swift-versions_1">#</a>
</h1>
<p>The <code class="prettyprint">.swift-version</code> file contains the Swift toolchain version your package needs. I tried changing it to a couple of different values with no success, either it would fail to download or fail to compile the dependencies. <a href="https://swiftenv.fuller.li">swiftenv</a> uses those version names to download the binary and it seems things are unstable regarding URLs. </p>
<h1 id="swift-package-manager_1">Swift Package Manager <a class="head_anchor" href="#swift-package-manager_1">#</a>
</h1>
<p>Notice I said <em>package</em> instead of application. That’s because it is a package. </p>
<pre><code class="prettyprint">import PackageDescription
let package = Package(
name: "TheSlackCommand",
dependencies: [
.Package(url: "https://github.com/kylef/Curassow.git", majorVersion: 0, minor: 4)
]
)
</code></pre>
<p>This isn’t something exclusive to server-side Swift and I expect Apple to add SPM to Xcode eventually. If the community starts supporting it and adding these <code class="prettyprint">Package.swift</code> files this might be a strong alternative to CocoaPods.</p>
<p>I had problems with dependencies. Curassow depends on a couple of other packages and I choose a Swift version that wasn’t compatible with some. Again, it’s all so early stage.</p>
<h1 id="if-oslinux_1">#if os(Linux) <a class="head_anchor" href="#if-oslinux_1">#</a>
</h1>
<p>I was used to an Apple controlled environment, OS X and iOS, but when deployed to Heroku Swift runs on Ubuntu. That meant some BSD functions <a href="https://bugs.swift.org/browse/SR-685">didn’t work</a> and Foundation <a href="https://bugs.swift.org/browse/SR-384">wasn’t quite as polished</a>. <br>
I’m positively surprised Foundation is present at all and it’s great to see <a href="https://github.com/apple/swift-corelibs-foundation">how active the project is</a>.</p>
<h1 id="the-middle-layer_1">The middle layer <a class="head_anchor" href="#the-middle-layer_1">#</a>
</h1>
<p>Ben suggests <a href="https://curassow.fuller.li">Curassow</a> as an HTTP server and I was glad to find it’s open source and designed to be fast and simple. So simple it went from great for starters to missing features very quickly, i.e. JSON parsing, sessions, multipart requests, etc.<br>
<a href="http://perfect.org">Perfect.org</a> looks more mature but apparently it can’t be added by just declaring it as a dependency. In the future I intend to try it but for now what I have works.</p>
<h1 id="deploying_1">Deploying <a class="head_anchor" href="#deploying_1">#</a>
</h1>
<p>Heroku was very easy to deploy, but at the first sign of trouble I was clueless where the logs where, error messages, anything. That and the mandatory sleep time pushed me to another platform. Since last week Heroku <a href="https://blog.heroku.com/archives/2016/5/18/announcing_heroku_free_ssl_beta_and_flexible_dyno_hours">announced</a> changes to it’s free dyno plan in terms of hours so I will try it again next time.</p>
<h1 id="ibm-bluemix_1">IBM Bluemix <a class="head_anchor" href="#ibm-bluemix_1">#</a>
</h1>
<p>The deploy was also super easy and for what I need is very similar to Heroku. Anyway I found it’s dashboard easier to use and was able to build what I needed using it.</p>
<hr>
<p>In summary I wouldn’t use Swift for anything serious on the server-side. There’s almost no information online and the tools aren’t as easy as you might be used to if you’re coming from iOS. On a positive note it’s great to see there’s multiple choices for cloud services and libraries already. For example <a href="http://www.zewo.io">Zewo</a> looks great and has Linux support right in the title. Swift has made my code better and it makes me happy to see such open community built around it.</p>
<p>?</p>
tag:fbernardo.org,2014:Post/how-we-work-at-mokriya2015-04-03T08:00:40-07:002015-04-03T08:00:40-07:00How we work at Mokriya<p>We can only expect to get better at what we do if we open it up to criticism. And in that spirit of openness I thought I would share a bit about Mokriya’s software development process. Maybe I can inspire some of you to try this at your workplace.</p>
<h2 id="what39s-mokriya_2">What’s Mokriya? <a class="head_anchor" href="#what39s-mokriya_2">#</a>
</h2>
<p><a href="http://mokriya.com">Mokriya</a> is a software development company based in Cupertino, but we have more than 30 employees around the world. The large majority of us work 100% remote.</p>
<p>I’ve been part of Mokriya for 8 months now, as an iOS Developer.</p>
<h2 id="how-do-we-synchronize_2">How do we synchronize <a class="head_anchor" href="#how-do-we-synchronize_2">#</a>
</h2>
<p>Each product has a dedicated team, so usually I only have to sync with three to six people. Finding time for a quick half an hour call every day is easy.</p>
<p>But syncing with the internal team is as important as syncing with the client and for the past months that’s also a daily call for me. </p>
<p>So I have at least two calls every day, 30 minutes each. That single hour saves us multiple ones reading and answering email threads. </p>
<p>In a remote environment good communication is <strong>absolutely necessary</strong> to keep speed and quality high.</p>
<h2 id="how-do-we-distribute-work_2">How do we distribute work <a class="head_anchor" href="#how-do-we-distribute-work_2">#</a>
</h2>
<p>At our daily syncs with the client we discuss new tasks, ideas and changes in the nightly build. That allows for more context on the why of some tasks, as well as technical problems being identified early. It keeps the client in the loop and the team gets time to ask questions.</p>
<p>The other daily sync is with the internal team. That’s when tasks are discussed and assigned. </p>
<p>The rest is Slack and some quick calls for <a href="http://blog.codinghorror.com/rubber-duck-problem-solving/">rubber ducking</a>.</p>
<h2 id="gitflow-is-perfect-for-the-distributed-workpl_2">Git-flow is perfect for the distributed workplace <a class="head_anchor" href="#gitflow-is-perfect-for-the-distributed-workpl_2">#</a>
</h2>
<p>By using <a href="http://nvie.com/posts/a-successful-git-branching-model/">git-flow</a> we are able to keep conflicts to a minimum and spend days working on one feature without slowing others down. </p>
<p>Another non-negligible benefit is the separation that comes with git-flow. We can focus on one feature at a time and it’s easier to trace a regression.</p>
<h2 id="code-review-makes-us-feel-more-confident-and_2">Code Review makes us feel more confident and learn fast <a class="head_anchor" href="#code-review-makes-us-feel-more-confident-and_2">#</a>
</h2>
<p>We actually use git-flow with a twist. Instead of finishing features, pull requests are created and wait for Code Review before being merged.</p>
<p>Since we’re currently using Swift, Code Review is also a fast way for all of us to learn it at the same pace and keep standards in our code.</p>
<h2 id="iterating-our-process-feels-natural_2">Iterating our process feels natural <a class="head_anchor" href="#iterating-our-process-feels-natural_2">#</a>
</h2>
<p>When we started working on this project we were committing directly to the <em>master</em> branch, then we moved to git-flow as the team and project grew. Code Review was later added to maintain code clarity. </p>
<p>In that time we already figured what’s the next step. We’re taking advantage of our Code Reviews and writing Mokriya’s Swift Coding Style Guide, which is itself being composed using pull requests and reviews.</p>
<h2 id="thoughts-on-my-experience_2">Thoughts on my experience <a class="head_anchor" href="#thoughts-on-my-experience_2">#</a>
</h2>
<p>I believe iteration is really the key here. But that wouldn’t be possible without good communication. </p>
<p>All this started at one of the daily syncs. Each of those improvements was suggested and we tried it.</p>
<p>I was actually one of the more conservative ones. I thought Code Review would just suck up time. I was wrong. It just doesn’t. </p>
<p>I have no idea where we’ll go from here, maybe unit testing, maybe tweaking Code Review. But I am sure we’ll keep improving and if it ends up not working we’ll step back and try another thing.</p>
<p><em>If you questions or comments about this you can always reach me on Twitter.</em></p>
tag:fbernardo.org,2014:Post/sharing-core-data-between-app-and-extension2015-02-19T18:01:01-08:002015-02-19T18:01:01-08:00Sharing Core Data between App and Extension<p>For years now I’ve been avoiding Core Data. My first experience with it was back when the iPad first came out and it wasn’t pleasant. </p>
<p>I was able to ignore it for so long because most of the projects I worked on were just client apps for some web service, with no need for local search, indexing or complex relationship graphs. So I was a little worried when I realised one of my projects needed all three.</p>
<p>I since discover my previous problems with Core Data were just part of the learning curve: threading and performance. With GCD Core Data gained support for queues and blocks, making it considerably easy to work with different threads. Performance is something that depends on the specific project but let’s say that knowing how Core Data actually fetches data from the data store helped a lot (RTFM). </p>
<p>For the project at hand I needed the Core Data store, and if possible context, synced locally between two processes: application and WatchKit extension.</p>
<p>The store file should be placed in a <a href="https://developer.apple.com/library/mac/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW21">shared container</a> and both processes could create a Core Data stack for that store. Then, when process A’s context is saved, process B can refresh it’s stack (or even better, merge the changes in it’s object context). If your data model is simple enough (mine is) you can get away with minimum merge situations.</p>
<p>Now my only problems were the save and refresh steps. Having to count on the user to refresh for new data to appear is not a great experience. Also, making objects appear seamsly on the Watch as the user adds them on the phone… That’s the effect I want, Magic!</p>
<p>The objects can be saved automatically. As the user adds an object the context gets saved, but communicating that to the other processes was out of the scope of Core Data. Luckily my attention was called to a <a href="http://ddeville.me/2015/02/interprocess-communication-on-ios-with-berkeley-sockets/">blog post</a> by Damien DeVille where he sums up the state of Interprocess communication on iOS and suggests the use of Berkeley Sockets.</p>
<p>You see, on Unix you can create a socket for a file. And multiple clients can “connect” to that file and communicate. Since the shared container is shared between application and extension that makes it the place to put that file.</p>
<p>That method is very interesting and can be used to, not only notify both processes that data has changed, but also to communicate what changed. And apparently Apple <a href="https://developer.apple.com/library/mac/technotes/tn2083/_index.html#//apple_ref/doc/uid/DTS10003794-CH1-SECTION31">prefers it to Mach ports</a> (<a href="http://ddeville.me/2015/02/interprocess-communication-on-ios-with-mach-messages/">which also work on iOS</a>).</p>
<p>In the end I decided to go with something simpler, the <a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/notify.3.html">notify routines</a>. Since those are stateless notifications, distributed by a system-wide notification server, you can notify as many clients as you want. Also, it’s dead simple to configure:</p>
<pre><code class="prettyprint lang-Swift">//Register for notifications
var registrationToken : Int32 = 0
notify_register_dispatch(
"org.fbernardo.app.coredata.refresh",
&registrationToken,
dispatch_get_main_queue()) {
[unowned self] token in
self.refresh()
}
//Post notification
notify_post("org.fbernardo.app.coredata.refresh")
</code></pre>
<p>Just remember that if your app registers for a given notification event it will be called even if the origin was the same app. Also, on the example above the main queue wouldn’t block because notify_post is asynchrounous. </p>
tag:fbernardo.org,2014:Post/clarity-in-swift2014-12-04T17:40:45-08:002014-12-04T17:40:45-08:00Clarity in Swift code<pre><code class="prettyprint lang-swift">var numbers = [-1, 0, -9, -3, 1, 3, 4]
let first = numbers.first!
let (min, max) = numbers.map({($0,$0)}).reduce((first,first), combine: {($0.0 < $1.0 ? $0.0 : $1.0, $0.0 > $1.0 ? $0.0 : $1.0)})
</code></pre>
<p>As you can probably guess, this Swift snippet compiles and works, it finds the minimum and the maximum values inside the <code class="prettyprint">numbers</code> array.</p>
<p>This code represents my biggest fear regarding Swift. I’m sure many people will actually enjoy this, most won’t care enough to think about it now, but I think this type of code is exactly what makes great languages hard for beginners to grasp. </p>
<p>First, is this is real production code? After all I choose this snippet to make a point. <strong>If it compiles someone will ship it, commit it and even share it.</strong> Of this I have no doubt.</p>
<p>I come up with this gibberish by “cleaning” up code:</p>
<pre><code class="prettyprint lang-swift">var numbers = [-1, 0, -9, -3, 1, 3, 4]
let first = numbers.first!
var min = first
var max = first
for i in numbers {
if i < min {
min = i
}
if i > max {
max = i
}
}
</code></pre>
<p>There’s nothing wrong with this code, it’s easy to understand, and it finds out the minimum and maximum while iterating the array only once. But I wanted it shorter, and with constants instead of variables.</p>
<pre><code class="prettyprint lang-swift">let min = numbers.reduce(first, combine: { $0 < $1 ? $0 : $1 })
let max = numbers.reduce(first, combine: { $0 > $1 ? $0 : $1 })
</code></pre>
<p>A bit weirder if you are not used to the <a href="https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/Closures.html">Shorthand Argument Names</a> but still readable. It now takes two iterations to find the values, but I’m more interested in clarity and conciseness.</p>
<pre><code class="prettyprint lang-swift">let (min, max) = numbers.map({($0,$0)}).reduce((first,first), combine: {($0.0 < $1.0 ? $0.0 : $1.0, $0.0 > $1.0 ? $0.0 : $1.0)})
</code></pre>
<p>This is where it gets ugly. I’m now using <code class="prettyprint">map</code> to create a list of tuples, then <code class="prettyprint">reduce</code> folds that into a tuple with the minimum and maximum. It won’t win a <a href="http://www0.us.ioccc.org/1988/westley.c">IOCCC</a>, but it’s not pretty.</p>
<p>Please don’t commit code like this. If you looked at those samples and thought: <em>“this is so stupid, why is he doing this?”</em>; you’re on the <em>right side</em>.<br>
Shorter code isn’t necessarily faster. You are not charged by the character. And if you, like me, are still on the fence between Objective-C and Swift, please prefer clear vs. short code despite what the language enables.</p>
tag:fbernardo.org,2014:Post/nskeyedunarchiver-and-swift2014-11-27T09:15:24-08:002014-11-27T09:15:24-08:00NSKeyedUnarchiver and Swift<p>Too many years using Objective-C (or any another language really) will give you a sixth sense. Let me show you an example: something in the back of your head should shout at the following code.</p>
<pre><code class="prettyprint lang-objc">NSString *string = [self stringOrNil];
NSURL *url = [NSURL URLWithString:string];
</code></pre>
<p>If you don’t see the problem don’t give up, you were not bitten enough times. The problem is that <code class="prettyprint">+[NSURL URLWithString:]</code> will throw an exception if <code class="prettyprint">URLString</code> is <code class="prettyprint">nil</code>. <br>
We can avoid this by checking if <code class="prettyprint">URLString</code> is <code class="prettyprint">nil</code>.</p>
<pre><code class="prettyprint lang-objc">NSString *string = [self stringOrNil];
NSURL *url = string ?[NSURL URLWithString:string] : nil;
</code></pre>
<p>Perfect. That’s what I do every project. I must keep in mind that <code class="prettyprint">+[NSURL URLWithString:]</code> does that. The compiler won’t force you to implement a try/catch block like in Java, so you must have this present while coding. That sucks.</p>
<p>Now let’s consider the case of NSKeyedUnarchiver:</p>
<pre><code class="prettyprint lang-objc">NSString *filePath = [self filePath]; //this is always a valid file path
[NSKeyedUnarchiver unarchiveObjectWithFile:filePath]
</code></pre>
<p>Again, you might recognise the same problem as before. <code class="prettyprint">+[NSKeyedUnarchiver unarchiveObjectWithFile:filePath]</code> will throw an exception if the file doesn’t contain a valid archive. But how can we test that in order to avoid the exception?</p>
<p><strong>You can’t. You shouldn’t.</strong> This is exactly why exceptions exist. To let you try something that you can’t guarantee will work, and catch a problem in the exceptional situation of one occurring. Deal with it.</p>
<pre><code class="prettyprint lang-objc">NSString *filePath = [self filePath]; //this is always a valid file path
id object = nil;
@try {
object = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
} @catch (NSException *exception) {}
</code></pre>
<p>That’s one way of doing it, if you don’t want to deal with the error. But what about Swift? <a href="https://devforums.apple.com/thread/228324?start=50&tstart=0#995390">Exceptions didn’t make it in time for 1.0.</a> If you decide to use <code class="prettyprint">NSKeyedUnarchiver.unarchiveObjectWithFile(_:)</code> there’s nothing you can do in <em>pure Swift</em> to make sure your app won’t crash. <strong>At least that I know off.</strong></p>
<p>I came up with a simple solution for this. Create a simple Objective-C category that provides the exception handling I need.</p>
<pre><code class="prettyprint lang-objc">@implementation NSKeyedUnarchiver (SwiftUtilities)
+ (id)su_unarchiveObjectWithFilePath:(NSString *)filePath {
id object = nil;
@try {
object = [self unarchiveObjectWithFile:filePath];
}
@catch (NSException *exception) {
object = nil;
}
return object;
}
@end
</code></pre>
<p>Then, after adding that to the <a href="https://developer.apple.com/library/ios/documentation/swift/conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_77">Bridging Header</a>, I call it in Swift.</p>
<pre><code class="prettyprint lang-swift">var object : AnyObject? = NSKeyedUnarchiver.su_unarchiveObjectWithFilePath(filePath)
</code></pre>
<p>This solution will still work if exceptions are introduced in Swift. And it’s so simple it shouldn’t require any changes for years to come. At least while Objective-C and Swift together are supported. If you know of a better way to do this I would be thrilled to hear from you via <a href="https://twitter.com/fbbernardo">Twitter</a>.</p>
tag:fbernardo.org,2014:Post/watchkit-day22014-11-21T09:52:42-08:002014-11-21T09:52:42-08:00WatchKit Day 2<p>Did I mention that WatchKit was limited? </p>
<p>So far so good, Xcode’s Beta is crashing on an acceptable rate, Swift is starting to make more sense (yes, I’m also starting with that) and I had the opportunity to say my first “no, you can’t do that on the watch”.</p>
<p>I spent a considerable amount of time setting up the project. I’m now using a framework to share code between App and Watch Extension. <strong>All in Swift.</strong> ?</p>
<p>The rest of the day was spent dealing with tables.</p>
<p>Using <a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceTable_class/index.html#//apple_ref/occ/instm/WKInterfaceTable">WKInterfaceTable</a> and configuring Row Controllers led me to wonder if those controllers were being reused. It makes sense to reuse cells in such a limited device. Probably they are being reused. Does that mean Row Controllers should implement the <code class="prettyprint">prepareForReuse:</code> method? No. <strong>You won’t find cells on WatchKit, only Row Controllers.</strong></p>
<p>Row Controllers are a concept introduced by Apple. Not a class, not a protocol, a documented concept. When you call <a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceTable_class/index.html#//apple_ref/occ/instm/WKInterfaceTable/rowControllerAtIndex:">rowControllerAtIndex:</a> you get an <code class="prettyprint">AnyObject!</code> back. </p>
<p>You can add row controllers to your table on the Watch App’s storyboard file. Those must have a name and a class (<code class="prettyprint">NSObject</code> by default). </p>
<p>You can then set/insert row types in code, upon initialization for example. And Row Controllers will be instantiated for you as soon as you call <br>
<a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceTable_class/index.html#//apple_ref/occ/instm/WKInterfaceTable/setRowTypes:">setRowTypes:</a>. </p>
<p>I found that those <strong>were not being reused</strong>. You have a row controller for each row. I assume cells are being reused in the device, but row controllers (that configure a cell) are not, those live in the extension and probably map to reusable cells on the watch. That’s why row controllers need a name.</p>
<p>This concept of Row Controllers is somewhat usual on iOS. When you need to keep some state about your <code class="prettyprint">UITableView</code> cells, that doesn’t belong in the model, it’s a good idea to keep another collection of controllers that keep that state.</p>
<p>Tomorrow I think I'l have a look at the testing options. Basic behaviour testing should be quite straightforward but we’ll see.</p>
tag:fbernardo.org,2014:Post/podcasts2014-11-21T09:39:21-08:002014-11-21T09:39:21-08:00My Podcast Subscriptions<p>Sometimes people ask me what podcasts I subscribe to. This is that list. If we share similar interests some of these require no introduction. If you are now starting with podcasts I suggest you download the last episode of each to see if you like it.</p>
<p>Many of those you can listen at any time. I usually have between a dozen and half a dozen to listen to.</p>
<ul>
<li><a href="http://atp.fm/">Accidental Tech Podcast</a></li>
<li><a href="http://www.coreint.org/">Core Intuition</a></li>
<li><a href="http://www.imore.com/debug/">Debug</a></li>
<li><a href="http://developingperspective.com/">Developing Prespective</a></li>
<li><a href="http://www.economist.com/podcast/itunes/All%20audio">The Economist: All Audio</a></li>
<li><a href="http://www.edgecasesshow.com/">Edge Cases</a></li>
<li><a href="http://exponent.fm/">Exponent</a></li>
<li><a href="http://www.wnyc.org/articles/freakonomics-podcast/">Freakonomics Radio</a></li>
<li><a href="http://www.hellointernet.fm/">Hello Internet</a></li>
<li><a href="http://ideveloper.co/podcast/">The iDeveloper Podcast</a></li>
<li><a href="http://www.imore.com/iterate">Iterate</a></li>
<li><a href="http://soundcloud.com/mokriya">Mokriya</a></li>
<li><a href="http://techdistortion.com/podcasts/pragmatic">Pragmatic</a></li>
<li><a href="http://therecord.co/">The Record</a></li>
<li><a href="http://releasenotes.tv/">Release Notes</a></li>
<li><a href="http://daringfireball.net/thetalkshow">The Talk Show With John Gruber</a></li>
</ul>
<h2 id="in-portuguese_2">In Portuguese <a class="head_anchor" href="#in-portuguese_2">#</a>
</h2>
<p>If you don’t speak Portuguese those are useless to you. If you do: experimenta!</p>
<ul>
<li><a href="http://www.tsf.pt/">TSF - Economia Dia-a-Dia</a></li>
<li><a href="http://www.tsf.pt/">TSF - Governo Sombra</a></li>
<li><a href="http://www.tsf.pt/">TSF - Pares da República</a></li>
<li><a href="http://www.tsf.pt/">TSF - Tubo de Ensaio</a></li>
<li><a href="http://www.tsf.pt/">TSF - Tudo é Economia</a></li>
</ul>
tag:fbernardo.org,2014:Post/watchkit-day-12014-11-20T11:18:59-08:002014-11-20T11:18:59-08:00WatchKit Day 1<p>So, <strong>WatchKit is here</strong>. It supports Glances, Actionable Notifications, and unexpectedly, something Apple calls <em>WatchKit Apps</em>.</p>
<p>I spent my first day reading the <a href="https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/WatchKitProgrammingGuide/index.html">programming guide</a>, watching the <a href="http://devstreaming.apple.com/videos/watch/Getting_Started_With_Watchkit/Getting_Started_With_Watchkit.m3u8">“getting started” video</a> and playing with Xcode 6.2 Beta. This post is a summary of what I learned. Have in mind that I focused most of my attention on WatchKit Apps and that this is a first Beta. Apple will make changes before the final release.</p>
<p>I must say that Xcode’s Beta surprised me in a good way. It crashed only once for the entire day, and I spent half an hour looking for a way to enable multiple lines in <a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceLabel_class/index.html#//apple_ref/occ/cl/WKInterfaceLabel">WKInterfaceLabel</a>, only to find out, after restarting Xcode, that the option was right there in Interface Builder.</p>
<p>WatchKit is <strong>very</strong> limited. What they call an App is just an interface living on the watch that sends user input to the phone, and the phone can send commands to change the interface on the watch. Put simply, <strong>no third party code running on Watch</strong>. I don’t expect this to change for the first release. </p>
<p>During the day I encountered many limitations. Most of them are understandable if you consider what’s happening behind the scenes. You see, practically any operation you perform on <a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceObject_class/index.html#//apple_ref/occ/cl/WKInterfaceObject">WKInterfaceObject</a> will be sent over-the-air to Watch. I don’t have specifics yet, maybe the phone is caching the messages and sending only a <code class="prettyprint">setNeedsDisplay:</code> in the end. <em>Maybe</em>.</p>
<p>My main concern is: Will simple actions be slow? How many of us will build WatchKit Apps for the first day, only to find out the app is terrible slow in the actual device. Notice the following code:</p>
<pre><code class="prettyprint lang-swift">import WatchKit
class TableInterfaceController : WKInterfaceController {
override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) {
let rowController : RowController = table.rowControllerAtIndex(rowIndex) as RowController
rowController.selected = !rowController.selected
}
}
</code></pre>
<ol>
<li>User taps a cell in the watch.</li>
<li>The watch sends a message to the phone that calls the method.</li>
<li>The method toggles the selected state for that specific row, which changes a group background color. This requires another message to be sent to the device.</li>
</ol>
<p>At least two messages are sent over-the-air to build this simple interaction. Now imagine if you send images.</p>
<p>Speaking about images, WatchKit provides a 20MB cache, per app, on the device. This is more than I expected and makes me consider if Apple is hinting us to use images for our custom UI needs.</p>
<p>Unfortunately, the cache seems to be missing a key feature (yes, I’ll open a feature request). There’s no way to check if a given image is on the cache. You can <a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceDevice_class/index.html#//apple_ref/occ/instm/WKInterfaceDevice/addCachedImage:name:">set an image for a given name</a>, you can provide <a href="https://developer.apple.com/library/prerelease/ios/documentation/WatchKit/Reference/WKInterfaceImage_class/index.html#//apple_ref/occ/instm/WKInterfaceImage">WKInterfaceImage</a> with a name instead of an image, but you can’t know if it was present or not.</p>
<p>The last thing I discovered was that you have to specify all the cells of a WKInterfaceTable <em>before</em> those are presented. There is no <code class="prettyprint">cellForRowAtIndexPath:</code>. </p>
<p>Also, if you need to share code between your app and the WatchKit extension, you should have a look at <a href="https://developer.apple.com/videos/wwdc/2014/#416">WWDC’s Session 416 - Building Modern Frameworks</a>. </p>
<p>In short, I’m very excited about WatchKit. The limitations are making me think of different ways to solve problems. It’s “first iPhone” fun. ?</p>
<p><em>Update: I just wanted to link to a couple of other posts on WatchKit and Watch that I find very well done.</em></p>
<ul>
<li><a href="http://furbo.org/2014/11/20/a-day-with-apple-watch/">A day with WATCH</a></li>
<li><a href="http://david-smith.org/blog/2014/11/18/getting-started-with-watchkit/">Getting Started with WatchKit</a></li>
<li><a href="http://natashatherobot.com">Natasha The Robot</a></li>
</ul>
tag:fbernardo.org,2014:Post/remotedatasource2014-08-28T05:25:39-07:002014-08-28T05:25:39-07:00Lighter View Controller Data Sources<p>Inspired by the concept of <a href="http://www.objc.io/issue-1/lighter-view-controllers.html">Lighter View Controllers</a>, neatly explained by <a href="https://twitter.com/chriseidhof">Chris Eidhof</a> on <a href="http://www.objc.io">objc.io</a>, I came up with a way of separating the view controller, data source and network code.</p>
<p>If you haven’t read the aforementioned article I suggest you do it and then come back to this page. </p>
<p>I started out with an <code class="prettyprint">ArrayDataSource</code> like Chris suggested:</p>
<pre><code class="prettyprint lang-objc">self.dataSource = [[ArrayDataSource alloc] initWithItems:photos
cellIdentifier:CellIdentifier
configureCellBlock:configureCell];
tableView.dataSource = self.dataSource;
</code></pre>
<h1 id="my-experience-using-arraydatasource_1">My experience using ArrayDataSource <a class="head_anchor" href="#my-experience-using-arraydatasource_1">#</a>
</h1>
<p>After some time three issues popped up:</p>
<ol>
<li>Most of my view controllers had collection/table views that present results from a web service call. <code class="prettyprint">ArrayDataSource</code> only supports arrays, so I had to fetch and parse from the server before creating the data source.</li>
<li>I needed pagination. That means my datasource should be able to grow.</li>
<li>I needed some modification features: move, replace, delete, etc…</li>
</ol>
<p>I could easily handle the first issue by creating the data source after the network call finished. The view controller would be the usual place for that code, but I wanted to keep it light.</p>
<p>The second issue could be handled by replacing the array with a bigger one each time I had to add a page.</p>
<p>The last was the trickiest. I was starting to have a lot of code outside the data source only to mutate it. That code should go inside the data source.</p>
<h1 id="enter-remotedatasource_1">Enter RemoteDataSource <a class="head_anchor" href="#enter-remotedatasource_1">#</a>
</h1>
<pre><code class="prettyprint lang-objc">@interface RemoteDataSource : NSObject
- (instancetype)initWithServiceURL:(NSURL *)serviceURL
cellIdentifier:cellIdentifier
configureCellBlock:configureCellBlock
pageParameterName:(NSString *)pageParameterName
parser:(id<RemoteDataSourceParserProtocol>)parser;
- (void)fetchWithCompletionBlock:(void (^)(NSError *error))block;
- (BOOL)fetchMoreWithCompletionBlock:(void (^)(NSError *error, NSArray *indexPaths))block;
- (void)cancel;
@end
</code></pre>
<pre><code class="prettyprint lang-objc">id<RemoteDataSourceParser> parser = ...
self.dataSource = [[RemoteDataSource alloc] initWithServiceURL:url
cellIdentifier:CellIdentifier
configureCellBlock:configureCellBlock
pageParameterName:@"page"
parser:aParser];
tableView.dataSource = self.dataSource;
</code></pre>
<p>As you can see I decided to separate the parsing code from the fetching code. The idea is that you might have different service results for each calls. For example, one for shops, one for locations, etc…</p>
<p>The parser protocol is also pretty straightforward:</p>
<pre><code class="prettyprint lang-objc">@protocol RemoteDataSourceParserProtocol
- (NSArray *)parseData:(NSData *)data error:(NSError **)error;
@end
</code></pre>
<p>As you can see, easy as pie to implement. Here’s an example:</p>
<pre><code class="prettyprint lang-objc">
@implementation ShopsRemoteParser
- (NSArray *)parseData:(NSData *)data error:(NSError **)error pageValue:(inout NSUInteger *)pageValue {
NSError *err;
id o = [NSJSONSerialization JSONObjectWithData:data options:0 error:&err];
if (err) {
if (error) *error = err;
return nil;
}
if (![o isKindOfClass:[NSArray class]]) {
if (error) *error = [NSError errorWithDomain:@"RemoteDataSourceParsingErrorDomain" code:0 userInfo:nil];
return nil;
}
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:[o count]];
for (id dict in o) {
if (![dict isKindOfClass:[NSDictionary class]]) continue;
id obj = [[Shop alloc] initWithInfo:dict];
if (obj) [arr addObject:obj];
}
return [arr copy];
}
@end
</code></pre>
<h1 id="what-should-a-data-source-do_1">What should a data source do? <a class="head_anchor" href="#what-should-a-data-source-do_1">#</a>
</h1>
<p>As the name implies, a data source should provide data to other object, frequently a view or view controller. So should it know how to create views? No it shouldn’t. That’s why Chris added that <code class="prettyprint">configureCellBlock</code>.</p>
<p><em>Just a quick note. I would love to know the reason behind <code class="prettyprint">tableView:cellForRowAtIndexPath:</code>. I mean, why did Apple decided it should be the data source’s job to create cells?</em></p>
<p>Let’s imagine you have a collection view of Flickr photos, as you scroll down the next page of items is appended to the bottom. When you tap one item you present a new view controller with a full screen collection view that shows the same photos. As you (horizontally) scroll to the end of this collection view the next page should be appended to the right.</p>
<p>You want both collection views to share the same data source. It’s the same data. And you want to reflect the same state on both as the user goes back and forth. But if the data source owns the cell identifier and configuration block you cannot share it between collection views. The cells are completely different.</p>
<h1 id="a-lighter-remotedatasource_1">A lighter RemoteDataSource <a class="head_anchor" href="#a-lighter-remotedatasource_1">#</a>
</h1>
<p>To be able to pass data sources around they can’t have any cell configuration code. So I refactored it into <code class="prettyprint">UIDataSource</code> and <code class="prettyprint">RemoteDataSource</code>. And while at it I also introduced <code class="prettyprint">AbstractDataSource</code>.</p>
<pre><code class="prettyprint">AbstractDataSource
RemoteDataSource
ArrayDataSource
UIDataSource
</code></pre>
<p><code class="prettyprint">UIDataSource</code> conforms to <code class="prettyprint">UITableViewDataSource</code> and <code class="prettyprint">UICollectionViewDataSource</code>. </p>
<pre><code class="prettyprint">@interface UIDataSource : NSObject <UICollectionViewDataSource, UITableViewDataSource>
@property(nonatomic, strong) AbstractDataSource *dataSource;
@property(nonatomic, copy, readonly) NSString *cellIdentifier;
- (instancetype)initWithDataSource:(AbstractDataSource *)dataSource cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(void (^)(id cell, id object, NSIndexPath *indexPath))block;
@end
</code></pre>
<p>Now each view controller can have a <code class="prettyprint">UIDataSource</code> and the inner <code class="prettyprint">AbstractDataSource</code> can be shared.</p>
<p><em>Note: This concept came to me after reading how <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Protocols/NSTableDataSource_Protocol/Reference/Reference.html"><code class="prettyprint">NSTableViewDataSource</code></a> works. Basically the data source only provides an object. It’s the cell’s job to display it.</em></p>
<h1 id="mutating-the-data-source_1">Mutating the data source <a class="head_anchor" href="#mutating-the-data-source_1">#</a>
</h1>
<p>The <code class="prettyprint">AbstractDataSource</code> class is actually just a definition of the needed methods and a placeholder implementation. A bunch of your typical <code class="prettyprint">NSAssert(@"implement this on a subclass");</code> methods. </p>
<p>It has methods for adding/removing/moving/replacing items, all with empty implementations. </p>
<pre><code class="prettyprint lang-objc">@interface AbstractDataSource : NSObject <UICollectionViewDataSource, UITableViewDataSource>
- (id)objectForKeyedSubscript:(NSIndexPath *)indexPath;
- (NSIndexPath *)indexPathForObject:(id)object;
- (NSUInteger)count;
- (void)insertObject:(id)object atIndexPath:(NSIndexPath *)indexPath;
- (BOOL)deleteItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)moveItemFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath;
- (void)replaceObjectAtIndexPath:(NSIndexPath *)indexPath withObject:(id)object;
@end
</code></pre>
<p>One last thing you might notice is that <code class="prettyprint">AbstractDataSource</code> still conforms to <code class="prettyprint">UICollectionViewDataSource</code> and <code class="prettyprint">UITableViewDataSource</code>. I figured that the data source needs to be able to define the number of sections and rows. If you have a <code class="prettyprint">DictionaryDataSource</code> with <em>{ title : array }</em> pairs for example.</p>
<p>It doesn’t make sense for a <code class="prettyprint">RemoteDataSource</code> to be modified, and the code to remove an item from <code class="prettyprint">ArrayDataSource</code> will certainly be different from <code class="prettyprint">SQLTableDataSource</code>.</p>
<h1 id="the-final-setup_1">The final setup <a class="head_anchor" href="#the-final-setup_1">#</a>
</h1>
<p>The way I described those classes is a simplification of the actual code I ended up with, but I think it’s enough to explain the concept. You can now add caching, errors, new data sources, etc…</p>
<p>This is just an idea. Everybody has a way of organizing code. This happens to be mine at the moment. The best one I found so far for these types of applications.</p>
<p>You can find a sample project on <a href="https://github.com/fbernardo/RemoteDataSourceSample">Github</a>.</p>
<p><em>I can’t recommend <a href="http://www.objc.io">objc.io</a> enough by the way.</em> </p>