<?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 Peter Livesey on Medium]]></title>
        <description><![CDATA[Stories by Peter Livesey on Medium]]></description>
        <link>https://medium.com/@peterlivesey?source=rss-30f43bddcaef------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*Hf1kZO60xVW_AU7H.</url>
            <title>Stories by Peter Livesey on Medium</title>
            <link>https://medium.com/@peterlivesey?source=rss-30f43bddcaef------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 29 Apr 2026 05:55:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@peterlivesey/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[All you never wanted to know about state in SwiftUI]]></title>
            <link>https://medium.com/device-blogs/all-you-never-wanted-to-know-about-state-in-swiftui-7314d0c51318?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/7314d0c51318</guid>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[home]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Mon, 09 Dec 2019 15:29:28 GMT</pubDate>
            <atom:updated>2019-12-09T15:29:28.309Z</atom:updated>
            <content:encoded><![CDATA[<p>I recently released <a href="https://apps.apple.com/us/app/id1480388057">an app</a> written 100% in SwiftUI and in doing so, uncovered some patterns that are difficult to express. In this post, I am going to explain how to set initial state in SwiftUI. It’s trickier than you’d expect.</p><h3>First, an overview</h3><p>There are three types of local state in SwiftUI:</p><ol><li>State that’s only controlled by this view</li><li>State that’s only controlled by a parent</li><li>State that’s controlled by both this view and its parent</li></ol><p>There’s also external state with environment variables and observables, but I’m going to ignore these in this post for brevity.</p><h4>State controlled by this view</h4><p>If you have some local state to keep track of, this is easy:</p><pre>struct MyView: View {<br>  @State private var toggleSelected = false<br>  ...</pre><p>This state can now be changed by MyView which will rerender whenever toggleSelected is edited. This state can be passed down to child views, but a parent cannot edit this state.</p><h4>State controlled by a parent</h4><p>Often, you want a parent view to control a variable without letting the child view edit it. This can be done with a simple instance variable.</p><pre>struct MyView: View {<br>  let text: String<br>  ...<br>}</pre><pre>struct ParentView: View {<br>  @State private var text = &quot;hello&quot;</pre><pre>  var body: some View {<br>    MyView(text: text)<br>  }<br>}</pre><p>At first glance, it may appear that text is immutable since it’s declared with let. However, whenever text on the parent changes, it will call body again and recreate a new instance of MyView with a new text value. This allows the parent to control the state of a child without allowing the child to edit this value.</p><h4>State controlled by both the parent and child</h4><p>And finally, sometimes you want state to be controlled by both the parent and the child. For this, you use a binding:</p><pre>struct MyView: View {<br>  @Binding var text: String<br>  ...<br>}</pre><pre>struct ParentView: View {<br>  @State private var text = &quot;&quot;</pre><pre>  var body: some View {<br>    MyView(text: $text)<br>  }<br>}</pre><p>Now, both the parent and child can change the value of text and they share this value. If either the parent change the value of text both views will rerender.</p><h3>A need for something different</h3><p>In my app, ZenDen, there’s a feature where you can reassign a task to someone else in your home. This view needs to keep track of which person is selected but it only actually changes if you tap save. So, it makes sense that only the child keeps track of this state. When you tap save, you can simply inform the parent view of this change through a completion block.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/282/1*jovpUYj_zHsR1eVy4Un0MA.png" /><figcaption>Users can reassign a task to someone else. If you select ‘Keep it fair’, it will automatically reassign future tasks to keep the load even.</figcaption></figure><p>Here’s the code so far:</p><pre>struct ReassignView: View {<br>  // Called with the selected assignee and keep it fair on save<br>  let saveTapped: (String, Bool) -&gt; Void<br>  @State var selectedAssignee = &quot;Anyone&quot;<br>  ...<br>}</pre><p>But there’s a product problem here. Currently, the view will always initialize selectedAssignee with Anyone . But, I wanted to set an initial value which is the current assignee for the task. So, if the task is currently assigned to me, I want the reassign view to pop up and show Peter as the selected assignee. I want to initialize the child’s state with an initial value. You’d think this would be easy by simply passing it in the initializer:</p><pre>struct ReassignView: View {<br>  @State var selectedAssignee = &quot;&quot;</pre><pre>  init(assignee: String) {<br>    selectedAssignee = assignee<br>  }<br>}</pre><p>Sadly, this <em>just doesn’t work</em>. No matter what you pass in as assignee, selectedAssignee will always be initialized to empty string. I can only speculate why this is the case, but it seems like @State can only be mutated outside of the init. Luckily, there’s a workaround:</p><pre>struct ReassignView: View {<br>  @State var selectedAssignee: String</pre><pre>  init(assignee: String) {<br>    _selectedAssignee = State(initialValue: assignee)<br>  }<br>}</pre><p>_selectedAssignee is a trick to access the wrapper object instead of the string. It has the type State&lt;String&gt; and here, it’s initialized with the assignee. Now, when it’s first initialized, the parent can control the initial value. After that, the ReassignView will control the value of selectedAssignee.</p><h3>But wait, there’s a bug?</h3><p>Consider the following code:</p><pre>// in the parent<br>var body: some View {<br>  ReassignView(assignee: &quot;Peter&quot;)<br>}</pre><ol><li>The parent creates the ReassignView with the initial value “Peter”</li><li>The ReassignView changes its internal state to “Alice”</li><li>The parent is rerendered for some reason (e.g. some unrelated state has changed)</li><li>init will be called on ReassignView and the assignee will be set back to “Peter”</li></ol><p>Won’t this cause a bug?</p><p><strong>Actually, no, it won’t.</strong> To understand why, we need to understand how SwiftUI injects state into View objects. Although SwiftUI is closed source and the documentation is currently non-existent, it seems to follow this sequence of events:</p><ol><li>Call init on the View</li><li>If there’s stored state for this view, set all the @State properties</li><li>Call body on the View</li></ol><p>So, even though in init, we set the initial value of selectedAssignee, this is always overridden before body is called if it’s previously been set. In this case, selectedAssignee will indeed be initialized with the value “Peter”, but it will be changed to “Alice” before body is called.</p><h3>But wait, isn’t this an antipattern?</h3><p>The main problem I have with this approach is that it’s not clear to the parent view that this is the behavior. The initializer looks identical to an initializer when the state is controlled by the parent. Consider these two side by side:</p><pre>Text(myText)<br>ReassignView(assignee: myAssignee)</pre><p>If myText changes, then the text will rerender on screen. However, if myAssignee changes, it will not update the ReassignView. Since this new view behaves differently from the stock SwiftUI views, one might consider this an antipattern.</p><p>I’ve adopted the convention of prefixing all of these initializer arguments with initial so the initializer becomes:</p><pre>ReassignView(initialAssignee: myAssignee)</pre><p>SwiftUI is still new and so it’s up to us (the community) to define conventions like this. Let me know in the comments what you think of this convention and if you have other ideas.</p><h3>Other ways to accomplish this</h3><p>Instead of this approach, you could simply make selectedAssignee a binding. However, this feels like it leaks implementation details to the parent since it doesn’t need to ever read this value. It also now needs to worry about resetting this value at the correct time (whenever a new ReassignView is presented). Ultimately, I think this makes it a worse approach.</p><p>You could also avoid setting the State with a default value:</p><pre>struct ReassignView: View {<br>  let initialAssignee: String<br>  @State private var storedAssignee: String? = nil<br>  private var selectedAssignee: String {<br>    get { storedAssignee ?? initialAssignee }<br>    set { storedAssignee = newValue }<br>  }<br>}</pre><p>However, this still falls to the same antipattern problems as my approach and requires significantly more boilerplate.</p><h3>Phew…that was crazy…</h3><p>Welcome to SwiftUI! 😛 It’s <a href="https://www.rei.com/blog/climb/fun-scale">fun</a>.</p><p>We’ve just released our <a href="https://apps.apple.com/us/app/id1480388057">new app — ZenDen</a>, and it’s written entirely with SwiftUI. If you have any questions about writing a production app in SwiftUI, let me know in the comments. I’m planning on writing a few more posts on SwiftUI, so let me know what to write next.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/207/1*CBvd25rH3VphDw4b0SA-nw.png" /><figcaption>Find some Zen with ZenDen</figcaption></figure><p>We wrote ZenDen to reduce the stress caused by organizing household tasks. The mental load of organizing a home often unfairly falls on one individual when most of this organization can be automated.</p><p>We’re always trying to improve, so let us know if you have any feedback on the app.</p><p>Thanks to Felix Lapalme for helping review this post.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7314d0c51318" width="1" height="1" alt=""><hr><p><a href="https://medium.com/device-blogs/all-you-never-wanted-to-know-about-state-in-swiftui-7314d0c51318">All you never wanted to know about state in SwiftUI</a> was originally published in <a href="https://medium.com/device-blogs">Device Blogs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Adding Advanced Features to your Network Stack in Swift]]></title>
            <link>https://medium.com/device-blogs/adding-advanced-features-to-your-network-stack-in-swift-941ecfff8dc3?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/941ecfff8dc3</guid>
            <category><![CDATA[code]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[networking]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Thu, 15 Aug 2019 15:33:31 GMT</pubDate>
            <atom:updated>2019-08-29T14:19:43.699Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This is part 2 of a series in writing an elegant and extensible network stack in Swift. You can read </em><a href="https://medium.com/device-blogs/writing-an-elegant-and-extensible-network-stack-in-swift-e2f5d9ab3ea9"><em>part 1 here</em></a><em>.</em></p><p>Writing your own networking stack is easy! One of the main advantages of owning your stack is that it’s simple to add additional features. You can pick and choose what you add depending on the specific needs of your application. You don’t need your stack to support every feature anyone could think of, but if you own your code, you can easily add in features when appropriate.</p><p>In this post, I’ll show a few examples of extending an existing stack. You may find some examples useful, while others may inspire you to add something else. Specifically, we’ll add:</p><ul><li>A DataConvertible protocol which will make returning non-models possible</li><li>The ability to cancel requests</li><li>Support for downloading files to disk</li><li>Background tasks</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*n8X7CQDfev1hP8JAIHaMeQ.jpeg" /><figcaption>Just keep adding features until you’ve got what you need. But hopefully, designed better than this. (Source: Buzzfeed)</figcaption></figure><h3>What we have so far</h3><p>In <a href="https://medium.com/device-blogs/writing-an-elegant-and-extensible-network-stack-in-swift-e2f5d9ab3ea9">part 1</a>, we built a simple networking stack which could handle GET and POST requests which also handled model parsing, status code errors and threading.</p><ol><li>It creates a URLRequestfrom a Requestable object</li><li>It creates a task and starts it</li><li>In the completion block, it checks for errors and then parses the Data into a model</li></ol><p>You can view <a href="https://github.com/plivesey/Network/blob/master/Network/Network/SimpleNetwork.swift">the full starter code here</a>, but here’s a condensed version:</p><pre>class Network {<br>  static let shared = Network()</pre><pre>  let session: URLSession = URLSession(configuration: .default)</pre><pre>  private let queue = DispatchQueue(label: &quot;Network&quot;, qos: .userInitiated, attributes: .concurrent)</pre><pre>  func send&lt;T: Model&gt;(_ request: Requestable, completion: <a href="http://twitter.com/escaping">@escaping</a> (Result&lt;T, Error&gt;)-&gt;Void) {<br>    queue.async {<br>      let urlRequest = request.urlRequest()</pre><pre>      // Send the request<br>      let task = self.session.dataTask(with: urlRequest) { data, response, error in<br>        let result: Result&lt;T, Error&gt;</pre><pre>        if let error = error {<br>          // First, check if the network just returned an error<br>          result = .failure(error)<br>        } else if let error = self.error(from: response) {<br>          // Next, check if the status code was valid<br>          result = .failure(error)<br>        } else if let data = data {<br>          // Otherwise, let&#39;s try parsing the data<br>          do {<br>            let decoder = JSONDecoder()<br>            result = .success(try decoder.decode(T.self, from: data))<br>          } catch {<br>            result = .failure(error)<br>          }<br>        } else {<br>          Log.assertFailure(&quot;Missing both data and error&quot;)<br>          result = .failure(NetworkError.noDataOrError)<br>        }</pre><pre>        DispatchQueue.main.async {<br>          completion(result)<br>        }<br>      }</pre><pre>      task.resume()<br>    }<br>  }<br>}</pre><h3>Data Convertible</h3><p>One problem with the current stack is that network requests always return a Model. This is the main use-case, but what if the network request doesn’t return anything? Or it returns binary data such as an image?</p><p>You have a couple of options. You could write a separate send function for each use-case, but you’d end up with a lot of duplicated code. Instead, let’s try a protocol-oriented approach:</p><pre>protocol DataConvertible {<br>  static func convert(from data: Data?) throws -&gt; Self<br>}</pre><pre>protocol RequiredDataConvertible: DataConvertible {<br>  static func convert(from data: Data) throws -&gt; Self<br>}</pre><pre>extension RequiredDataConvertible {<br>  static func convert(from data: Data?) throws -&gt; Self {<br>    if let data = data {<br>      return try convert(from: data)<br>    } else {<br>      throw DataConversionError(&quot;Missing data&quot;)<br>    }<br>  }<br>}</pre><p>For most types, it’s useful to convert non-optional Data, so there’s a wrapper protocol, RequiredDataConvertible for convenience. We can change our send function to:</p><pre>func send&lt;T: DataConvertible&gt;(_ request: Requestable, completion: <a href="http://twitter.com/escaping">@escaping</a> (Result&lt;T, Error&gt;)-&gt;Void) {<br>  // ...<br>  } else {<br>    do {<br>      result = .success(try T.convert(from: data))<br>    } catch {<br>      result = .failure(error)<br>    }</pre><p>And now, we can make any type we want adhere to DataConvertible.</p><pre>extension Data: RequiredDataConvertible {<br>  static func convert(from data: Data) throws -&gt; Data {<br>    return data<br>  }<br>}</pre><pre>// You can use this to return no data<br>struct Empty: DataConvertible {<br>  static func convert(from data: Data?) throws -&gt; Empty {<br>    return Empty()<br>  }<br>}</pre><p>You could also easily add support for strings, images, dictionaries, arrays, or anything else your app may need.</p><p>Sadly, making Decodable is a little trickier as you can’t simply extend Decodable to be DataConvertible. Data is also Decodable, so you end up with ambiguous types. To get around this, we need to use type erasure:</p><pre>struct DecodableConvertible&lt;T: Model&gt;: RequiredDataConvertible {<br>  let model: T</pre><pre>  init(_ model: T) {<br>    self.model = model<br>  }</pre><pre>  static func convert(from data: Data) throws -&gt; DecodableConvertible&lt;T&gt; {<br>    let decoder = JSONDecoder()<br>    let model = try decoder.decode(T.self, from: data)<br>    return DecodableConvertible(model)<br>  }<br>}</pre><p>And then we need to add another send method to Network:</p><pre>func send&lt;T: Model&gt;(_ request: Requestable, completion: <a href="http://twitter.com/escaping">@escaping</a> (Result&lt;T, Error&gt;)-&gt;Void) {<br>  return send(request) { (result: Result&lt;DecodableConvertible&lt;T&gt;, Error&gt;) in<br>    // We want to return T, so we should map to the inner model<br>    completion(result.map { $0.model })<br>  }<br>}</pre><p>Effectively, we’re creating a wrapper struct to hold the inner model. Then, we return this struct from the network stack and map out the inner model. The type erasure technique is common, and you can <a href="https://medium.com/swiftworld/swift-world-type-erasure-5b720bc0318a">learn more about it here</a>.</p><p>By the way, this type erasure is the reason why we need the Model protocol (<a href="https://medium.com/device-blogs/writing-an-elegant-and-extensible-network-stack-in-swift-e2f5d9ab3ea9">remember how we used that instead of </a><a href="https://medium.com/device-blogs/writing-an-elegant-and-extensible-network-stack-in-swift-e2f5d9ab3ea9">Decodable for the models?</a>). Now, if you pass in a Model as a return type, it will use the DecodableConvertible struct, but if you pass in Data, it will use the extension on Data to do the conversion. That may seem like a lot to follow, but if you’re confused, try <a href="https://github.com/plivesey/Network">checking out the code</a> and use Decodable instead of Model.</p><h3>Cancelling Requests</h3><p>NSURLSession allows cancelling of requests, but currently, our network stack does not. We can’t simply return a URLSessionTask because our stack is completely asynchronous (which is a good thing). There’s a solution though — we just need to write a class to handle canceling before the request is sent.</p><pre>class NetworkTask {<br>  private var task: URLSessionTask?<br>  private var cancelled = false</pre><pre>  private let queue = DispatchQueue(label: &quot;com.peterlivesey.networkTask&quot;, qos: .utility)</pre><pre>  func cancel() {<br>    queue.sync {<br>      cancelled = true</pre><pre>      // If we already have a task cancel it<br>      if let task = task {<br>        task.cancel()<br>      }<br>    }<br>  }<br>  <br>  func set(_ task: URLSessionTask) {<br>    queue.sync {<br>      self.task = task</pre><pre>      // If we&#39;ve cancelled the request before the task was set, let&#39;s cancel now<br>      if cancelled {<br>        task.cancel()<br>      }<br>    }<br>  }<br>}</pre><p>This class simply saves the cancel request and once the task is set, it will cancel it immediately. The only thing to remember is to use a DispatchQueue to keep everything thread-safe. Then, just update the send function:</p><pre>func send&lt;T: DataConvertible&gt;(...) -&gt; NetworkTask {<br>  <strong>let</strong> networkTask = NetworkTask()<br>  queue.async {<br>    // ...<br>    task.resume()<br>    networkTask.set(task)<br>  }<br>  return networkTask<br>}</pre><p>Though that session task is set asynchronously, we can immediately return our empty task since it can be cancelled at any time.</p><h3>Adding Background Tasks</h3><p>When your app goes to the background, usually all network tasks are cut off. This creates a really bad user experience. If users switch apps quickly, they’ll see error messages when they return to the app. Luckily, Apple provides a really easy API to solve this, and you can add it directly into the stack for every request. Just add to your send method:</p><pre>func send(...) {<br>  let backgroundTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)<br>  // ... after all the main logic, when you finish:<br>  DispatchQueue.main.async {<br>    completion(result)<br>    UIApplication.shared.endBackgroundTask(backgroundTaskID)<br>  }<br>}</pre><h3>File Download Support</h3><p>File downloading is similar to downloading data, but it has a slightly different API. You could simply copy-paste your existing code and change the necessary lines, but I prefer to share the code.</p><p>This is a little tricky, but possible with some creative closures. First, we need to change our send method slightly and also make it private (because this API isn’t exactly user friendly):</p><pre>private func send&lt;DataType, ReturnType&gt;<br>(_ request: Requestable,<br> taskCreator: <a href="http://twitter.com/escaping">@escaping</a> ((URLRequest, <a href="http://twitter.com/escaping">@escaping</a> (DataType?, URLResponse?, Error?)-&gt;Void)-&gt;URLSessionTask),<br> dataConvertor: <a href="http://twitter.com/escaping">@escaping</a> (DataType?) throws -&gt; ReturnType,<br> completion: <a href="http://twitter.com/escaping">@escaping</a> (Result&lt;ReturnType, Error&gt;)-&gt;Void)<br> -&gt; NetworkTask {</pre><p>Let’s decode what’s happened here:</p><ul><li>There’s an additional generic parameter: DataType</li><li>The first parameter is still just the request</li><li>The second parameter is a closure which converts a URLRequest and completion block into a data task</li><li>The third parameter is a closure which converts a DataType into a ReturnType</li><li>The final parameter is the completion block</li></ul><p>Now, let’s convert our original send function to use this helper function.</p><pre>func send&lt;T: DataConvertible&gt;(request, completion) -&gt; NetworkTask {<br>  return send(<br>    request,<br>    taskCreator: { session.dataTask(with: $0, completionHandler: $1) },<br>    dataConvertor: { try T.convert(from: $0) },<br>    completion: completion<br>  )<br>}</pre><p>The second parameter creates a data task from the session object. This is just a one-liner. The third parameter simply calls the DataConverible convert function.</p><p>We can write a similar function to wrap download requests:</p><pre>func download<br>(_ request: Requestable,<br> destination: URL,<br> completion: <a href="http://twitter.com/escaping">@escaping</a> (Result&lt;Empty, Error&gt;)-&gt;Void) -&gt; NetworkTask<br>{<br>return send(<br>  request,<br>  taskCreator: { session.downloadTask(with: $0, completionHandler: $1) },<br>  dataConvertor: { try self.moveFile(from: $0, to: destination) } },<br>  completion: completion)<br>}</pre><p>This function takes a request and a destination URL and downloads a file to that location. The second parameter creates a download task instead of a data task. The third parameter takes the temporary URL returned by the download task and <a href="https://github.com/plivesey/Network/blob/master/Network/Network/Network.swift#L158">moves the file from that location to the passed in location</a>.</p><p>Now, you just need to update the send code to use these task creator and data convertor tasks. This is relatively simple, but if you’re interested in the details, <a href="https://github.com/plivesey/Network">you can check out the full code here</a>.</p><h3>Other Ideas</h3><p>Remember, you don’t need to add any of these features if it’s not appropriate for your app. These are only examples of things you may want to add.</p><p>When building the <a href="https://apps.apple.com/us/app/navigator-meeting-assistant/id1466919451">Navigator app</a>, I added even more features including redirect handling, unzip support for files, and parsing custom errors. (If you’re interested in working with a stack like that, <a href="https://aspen.team/careers/">they’re hiring</a>).</p><p>The key takeaway here is that if you own your network stack, <em>it’s yours</em>. You can mold it into whatever your app needs.</p><p><em>This project and article will need to evolve as Swift and Foundation change. If you have any suggestions, comments, improvements, bugs, please let me know in the comments or </em><a href="https://github.com/plivesey/Network/pulls"><em>submit a PR to the Github project</em></a><em>.</em></p><p><em>Thanks to Alice Avery and </em><a href="https://twitter.com/kamilah"><em>Kamilah Taylor</em></a><em> for reviewing this post.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=941ecfff8dc3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/device-blogs/adding-advanced-features-to-your-network-stack-in-swift-941ecfff8dc3">Adding Advanced Features to your Network Stack in Swift</a> was originally published in <a href="https://medium.com/device-blogs">Device Blogs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Writing an Elegant and Extensible Network Stack in Swift]]></title>
            <link>https://medium.com/device-blogs/writing-an-elegant-and-extensible-network-stack-in-swift-e2f5d9ab3ea9?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/e2f5d9ab3ea9</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[networking]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Sat, 10 Aug 2019 11:04:55 GMT</pubDate>
            <atom:updated>2019-08-29T14:18:02.675Z</atom:updated>
            <content:encoded><![CDATA[<p>Apple constantly updates their networking APIs to make them easier to use. However, I find that a lot of people still are hesitant to write their own networking layer and choose to rely on common open source solutions.</p><p>Writing your own networking stack has several benefits. To name just a few:</p><ul><li>Avoids a 3rd party dependency which will need upgrading</li><li>More understandable code (since you wrote it!)</li><li>More extensible</li><li>Easier to debug, add logs, and add performance monitoring</li><li>Much easier to add advanced functionality</li><li>Allows you to parse errors from your backend into a specific model</li><li>Makes it easy to support custom error handling such as 401 or 500 status codes</li></ul><p>Plus, it’s now just really easy! In this article, I’m going to go over the basics. By the end of this post, you’ll have a network stack that can easily send GET and POST requests with model parsing with little boilerplate.</p><pre>let request = Request(path: &quot;users/1&quot;)<br>Network.shared.send(request) { (result: Result&lt;User, Error&gt;) in<br>  switch result {<br>    case .success(let user):<br>      print(user)<br>    case .failure(let error):<br>      print(error)<br>  }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*WWX1aNqa8Bzhqu_2OD0L7w.jpeg" /><figcaption>With codable, NSURLSession, and generics, writing your own networking stack is easier than ever</figcaption></figure><p>In a follow-up post, I’ll show how you can upgrade this simple network stack with more advanced features such as background tasks, file downloads, cancelable requests, and more.</p><h3>Setup</h3><p>First, let’s create a new file, Network.swift and add a singleton accessor, a session variable, and a basic send function:</p><pre><strong>class</strong> Network {<br>  <strong>static</strong> <strong>let</strong> shared = Network()<br>  <strong>let</strong> session: URLSession = URLSession(configuration: .default)</pre><pre><strong>  func</strong> send(<strong>_</strong> request: URLRequest,<br>            completion: <strong>@escaping</strong> (Result&lt;Data, Error&gt;)-&gt;Void) {}<br>}</pre><p>The send function takes a request and a completion block which returns a Result with either data or an error. Now, let’s fill this in with a simple implementation:</p><pre>Log.verbose(&quot;Send: \(urlRequest.url?.absoluteString ?? &quot;&quot;)&quot;)</pre><pre><strong>let</strong> task = session.dataTask(with: request) { data, response, error <strong>in</strong><br>  let result: Result&lt;T, Error&gt;<br>  if let error = error {<br>    // First, check if the network just returned an error<br>    result = .failure(error)<br>  } else if let data = data {<br>    result = .success(data)<br>  } else {<br>    Log.assertFailure(&quot;Missing both data and error from NSURLSession.&quot;)<br>    result = .failure(NetworkError.noDataOrError)<br>  }</pre><pre>  DispatchQueue.main.async {<br>    completion(result) <br>  }<br>}</pre><pre>// Make sure to call resume on the task or nothing will happen!<br>task.resume()</pre><p>Most of the code here is straightforward, but you’ll notice a couple of interesting things about this implementation:</p><ol><li>I created a simple NetworkError enum for some basic errors.</li><li>I’ve added some Log statements to the code. This is one of the benefits of your own networking stack! You can add your own Log statements where you see fit. <a href="https://github.com/plivesey/Network/blob/master/Network/Log/Log.swift">Here’s my implementation</a> or <a href="https://medium.com/device-blogs/assertions-in-production-e587fef5bfbc">previous post on assertions in code</a>.</li></ol><h3>Models</h3><p>This send function works fine, but it isn’t much better than just using URLSession directly. In most cases, we don’t want Data returned, but a model. So, let’s add a Model protocol and add support for parsing.</p><pre><strong>protocol</strong> Model: Codable {}</pre><p>It’ll become clear in a future post why we create this empty protocol instead of using Codable directly. Just trust me for now.</p><pre><strong>func</strong> send&lt;T: Model&gt;(<strong>_</strong> request: URLRequest, completion: <strong>@escaping</strong> (Result&lt;T, Error&gt;)-&gt;Void) {</pre><pre>...</pre><pre>} else if let data = data {<br>  do {<br>    let decoder = JSONDecoder()<br>    result = .success(try decoder.decode(T.self, from: data))<br>  } catch {<br>    result = .failure(error)<br>  }<br>}</pre><p>Simple. We just change the send function to be generic and add the JSONDecoder handling. When we call this function, we’ll be returned a model to immediately use in application code.</p><h3>Better Requests</h3><p>The URLRequest object is a little verbose to use, so instead, let’s create a wrapper object to make creating requests easier. Instead of using inheritance, I prefer a protocol-oriented architecture:</p><pre>protocol Requestable {<br>  func urlRequest() -&gt; URLRequest<br>}</pre><pre>struct Request: Requestable {<br>  let path: String<br>  let method: String</pre><pre>  init(path: String, method: String = &quot;GET&quot;) {<br>    self.path = path<br>    self.method = method<br>  }</pre><pre>  func urlRequest() -&gt; URLRequest {<br>    guard let url = URL(string: &quot;BASE_URL&quot;) else {<br>      Log.assertFailure(&quot;Failed to create base url&quot;)<br>      return URLRequest(url: URL(fileURLWithPath: &quot;&quot;))<br>    }</pre><pre>    var request = URLRequest(url: url.appendingPathComponent(path))<br>    request.httpMethod = method</pre><pre>    return request<br>  }<br>}</pre><pre>extension URLRequest: Requestable {<br>  func urlRequest() -&gt; URLRequest { return self }<br>}</pre><p>This new Request object includes the base url for your server so you can simply specify a path and a method. We can also easily make URLRequest adhere to Requestable in case we do want to make requests to other servers.</p><p>Updating our send method to use this new protocol is trivial:</p><pre><strong>func</strong> send&lt;T: Model&gt;(<strong>_</strong> request: Requestable, completion: <strong>@escaping</strong> (Result&lt;T, Error&gt;)-&gt;Void) {<br>  let urlRequest = request.urlRequest()<br>  ...</pre><h3>Post Requests</h3><p>When sending a POST request, you often send JSON data as part of the request. Of course, we don’t want to format that ourselves. How about using a Model? Let’s add a PostRequest struct:</p><pre>struct PostRequest&lt;Model: Encodable&gt;: Requestable {<br>  let path: String<br>  let model: Model</pre><pre>  func urlRequest() -&gt; URLRequest {<br>    guard let url = URL(string: &quot;BASE_URL&quot;) else {<br>      Log.assertFailure(&quot;Failed to create base url&quot;)<br>      return URLRequest(url: URL(fileURLWithPath: &quot;&quot;))<br>    }</pre><pre>    var request = URLRequest(url: url.appendingPathComponent(path))<br>    request.httpMethod = &quot;POST&quot;</pre><pre>    do {<br>      let encoder = JSONEncoder()<br>      let data = try encoder.encode(model)<br>      urlRequest.httpBody = data<br>      urlRequest.setValue(&quot;application/json&quot;,<br>                          forHTTPHeaderField: &quot;Content-Type&quot;)<br>    } catch let error {<br>      Log.assertFailure(&quot;Post request model parsing failed&quot;)<br>    }</pre><pre>    return urlRequest<br>  }<br>}</pre><p>Now, you can send models up to the server as POST requests. For example:</p><pre>let newUser = User(id: 2, name: &quot;Peter&quot;)<br>let request = PostRequest(path: &quot;/users&quot;, model: newUser)<br>Network.shared.send(request) { (result: Result&lt;Empty, Error&gt;) in<br>  print(result)<br>}</pre><h3>Status Code Errors</h3><p>One gotcha of URLSession is that it doesn’t handle status code errors. Luckily, adding logic to parse the status code is easy. And in the future, you could also handle specific status codes like unauthorized errors.</p><pre>struct StatusCodeError: Error {<br>  let code: Int<br>}</pre><pre>private func error(from response: URLResponse?) -&gt; Error? {<br>  guard let response = response as? HTTPURLResponse else {<br>    Log.assertFailure(&quot;Missing http response&quot;)<br>    return nil<br>  }</pre><pre>  let statusCode = response.statusCode</pre><pre>  if statusCode &gt;= 200 &amp;&amp; statusCode &lt;= 299 {<br>    return nil<br>  } else {<br>    Log.error(&quot;Invalid status code: \(statusCode)&quot;)<br>    return StatusCodeError(code: statusCode)<br>  }<br>}</pre><p>Next, add this check to the send function:</p><pre>if let error = error {<br>  result = .failure(error)<br>} else if let error = self.error(from: response) {<br>  result = .failure(error)<br>} else if let data = data {<br>  ...</pre><h3>Threading</h3><p>And for the last touch, let’s make this a bit more performant. URLSession already runs all networking operations on a background thread, and our model parsing for Get requests is on a background thread. But, when urlRequest() is called, it may cause some JSON parsing to run on the main thread. I recommend wrapping everything inside of send <a href="https://github.com/plivesey/Network/blob/297e6998665831901d15d1585e20a191c6f71071/Network/Network/SimpleNetwork.swift#L44">inside of an async block</a>. With that change, send won’t do <em>any</em> work on the main thread.</p><h3>Getting the Code</h3><p>If you’d prefer to just copy-paste code into your own project, you can find all the code for a full network stack (and a few examples) in <a href="https://github.com/plivesey/Network">this Github project</a>. The code for this article is shown in <a href="https://github.com/plivesey/Network/blob/master/Network/Network/SimpleNetwork.swift">SimpleNetwork.swift</a>.</p><h3>See It in Action</h3><p>I wrote a similar network stack to this in the <a href="https://apps.apple.com/us/app/navigator-meeting-assistant/id1466919451">Navigator app</a>, which helps make your meetings more productive. Of course, you can’t actually see the network stack…but hopefully, you can <em>feel</em> the elegant code through the app 😉. And, if you’re interested in working with code like this, <a href="https://aspen.team/careers/">they’re hiring</a>.</p><h3>Next time…</h3><p>This post just outlines the basics of getting a lightweight network stack up and running. With some customization, this should be enough for most apps. <a href="https://medium.com/device-blogs/adding-advanced-features-to-your-network-stack-in-swift-941ecfff8dc3">In the next post</a>, I’ve included some more advanced features that really show the power and benefit of building your own stack.</p><p><em>This project and article will need to evolve as Swift and Foundation change. If you have any suggestions, comments, improvements, bugs, please let me know in the comments or </em><a href="https://github.com/plivesey/Network/pulls"><em>submit a PR to the Github project</em></a><em>.</em></p><p><em>Thanks to Alice Avery and </em><a href="https://twitter.com/kamilah"><em>Kamilah Taylor</em></a><em> for reviewing this post.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e2f5d9ab3ea9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/device-blogs/writing-an-elegant-and-extensible-network-stack-in-swift-e2f5d9ab3ea9">Writing an Elegant and Extensible Network Stack in Swift</a> was originally published in <a href="https://medium.com/device-blogs">Device Blogs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Many Offline Options for iOS Apps]]></title>
            <link>https://medium.com/device-blogs/the-many-offline-options-for-ios-apps-2922c9b3bff3?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/2922c9b3bff3</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[offline]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[cache]]></category>
            <category><![CDATA[mobile-development]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Wed, 09 Jan 2019 04:27:17 GMT</pubDate>
            <atom:updated>2019-12-21T01:15:55.147Z</atom:updated>
            <content:encoded><![CDATA[<p>Offline mode is no longer just an extra feature you could choose to add to your app — it’s something many users expect. I’ve often seen developers force their <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/index.html">favorite offline solution</a> on a problem that could be solved in a better way.</p><p>There are many different ways of making an app work offline, each with advantages and drawbacks. There’s no magic bullet that will work every time, so it’s up to you to carefully weigh your options. Sometimes, the best solution may be a combination of several different technologies!</p><p>The main solutions available to make the app work offline are:</p><ul><li>A database, such as <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/index.html">Core Data</a> or <a href="https://realm.io/">Realm</a></li><li>A <a href="https://medium.com/@katedoesdev/normalized-vs-denormalized-databases-210e1d67927d">denormalized</a> cache, such as <a href="https://github.com/pinterest/PINCache">PINCache</a> or <a href="https://nshipster.com/nsurlcache/">NSURLCache</a></li><li>A <a href="https://medium.com/@katedoesdev/normalized-vs-denormalized-databases-210e1d67927d">normalized</a> model, cache such as <a href="https://plivesey.github.io/RocketData/">Rocket Data</a></li><li>Saving data to <a href="https://developer.apple.com/documentation/foundation/filemanager">the file system</a></li></ul><p><strong>There are many different ways to implement an offline mode, and you should always try to select the right tool for your app.</strong> But first, why should you make your app work offline?</p><h3>Why is offline important?</h3><p>First of all, <em>speed matters</em>. <a href="https://www.thinkwithgoogle.com/marketing-resources/experience-design/mobile-page-speed-load-time/">40% of users abandon pages which take more than 3 seconds to load</a>. People expect apps will be responsive and snappy. If they see a loading spinner for too long, they’ll just leave your app and open up one of the many other <a href="https://www.theguardian.com/commentisfree/2018/may/27/world-distraction-demands-new-focus">attention grabbers on their phone</a>. But, if your app works offline, it will be fast even in poor network connectivity.</p><p>Second, Business2Community estimates that <a href="https://www.digitaldoughnut.com/articles/2018/february/why-you-should-develop-an-offline-mobile-app">15% of the app usage at any time in the US is offline</a>, and in international markets, this is likely to be even higher. You users may be <a href="https://blog.superhuman.com/architecting-a-web-app-to-just-work-offline-part-1-8697f316c0eb">on a plane, in a cafe with a flaky connection, or on the subway</a>, and their internet could be coming in and out. If your app doesn’t work in these conditions, they will simply stop using your app.</p><h3>Caches vs. Databases</h3><p>When implementing an offline solution, the first step is to decide between a cache or a database. Databases can be powerful, but are overused by developers. Caches are simpler and are a better fit for many applications.</p><p>The most common database solutions are <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/index.html">Core Data</a> and <a href="https://realm.io/">Realm</a>, though many people prefer to use SQLite directly. You define models, load data from the network, and insert it into your database. Then, your view controllers listen to queries on the database and update whenever the data changes.</p><p>When implementing a cache, you load data from the cache and the network in parallel. The cached data doesn’t need to be structured and can simply be a serialized version of the data from the network. This means that loading data from the network and the cache look identical from a code perspective. There are many open source implementations of caches; <a href="https://github.com/pinterest/PINCache">PINCache</a> and <a href="https://nshipster.com/nsurlcache/">NSURLCache</a> are two common options.</p><p><strong>Databases are good if:</strong></p><ul><li>You can download all of the data for a user and store it locally without using <a href="https://www.imore.com/how-stop-facebook-making-your-iphone-run-crap">too much disk space</a>.</li><li>You can easily write logic that limits the data used on the device.</li><li>You need to be able to do simple, local searches over thousands of records.</li></ul><p><strong>Caches are good if:</strong></p><ul><li>You cannot download all the data for a user and need a simple eviction strategy.</li><li>You’ve already written logic to download data from the network and want to add in an offline mode without rewriting your application.</li><li>You want a simpler, lightweight, and flexible solution.</li></ul><p><strong>The problems with databases:</strong></p><ul><li>They are notoriously difficult to get right. You should expect to spend a decent amount of developer time dealing with crashes in this part of your application.</li><li>You need to write models and migrate them whenever something changes.</li><li>Deleting models to free up space is really difficult as it’s impossible to tell which models are currently in use by screens.</li></ul><p>Despite the downsides and overuse of databases, for some applications, it’s a great option. For example, a database would work well for a podcast player. You can download a reasonable number of upcoming episodes, and it’s easy to know when to delete models (once the user finishes an episode). Another example is a saving a game, as the user will never want to have a saved game deleted (unless they delete it manually).</p><p>On the other hand, a social media application would be much better suited with a cache. It’s impossible to download all the content for a user, and as they browse, a database would get larger and larger. In a similar vein, a news reader application would be much better with a cache. As the user browses new articles, a database wouldn’t stop growing. A cache easily stores everything you’ve recently viewed and automatically purges older articles. Additionally, you never need to migrate models or worry about <a href="https://cocoacasts.com/what-is-a-core-data-fault">data faults</a>.</p><h3>Normalized vs. Denormalized Data</h3><p>There are two main ways to store data in a cache — using normalized or denormalized data. Most application data can be visualized as a tree-like structure. It has a root model and then several child models (which then in turn could have more child models). When caching this data, you could simply store the entire tree as one entry in the cache. This will look something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zcGf5em6tg3jUXSXB9Hahg.png" /><figcaption>A denormalized or ‘tree-like’ cache</figcaption></figure><p>This is the simplest way to use a cache. You can implement it with just a few lines of code and it’s easy to pick unique ids for objects (for instance, you could store each object by the URL you used to fetch it).</p><p>However, you’ll notice that the author object is inserted twice into the database as a nested object. This means if you update the article with id=3 with an updated author object, next time you read article with id=42, you’ll get the old author. If this type of consistency is important, you could consider ‘normalizing’ your data before you cache it. This means ripping apart the tree into submodels and caching each model under a unique id. For example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VNsJF55KogRf34_WNWK_Bw.png" /><figcaption>A normalized cache</figcaption></figure><p>Note that this is not a database! Each entry is still a blob of unstructured data keyed by an id. This means you still won’t need migrations when models change and eviction is simple. However, implementing this system is not simple as you also need to write logic to reconstruct models and have unique ids for each submodel.</p><p>Note: because of the overhead of storing the dotted line ‘pointers’ above, this solution actually doesn’t use less space than a denormalized cache. See the ‘Additional Tips’ section for more info.</p><p>I’ve previously <a href="https://engineering.linkedin.com/blog/2016/07/rocket-data--faster-model-management-for-ios">written about using this strategy for the LinkedIn App</a>, and the <a href="https://github.com/plivesey/RocketData">code that powers consistency amongst models is open-source</a>. Using this solution, adding offline behavior was easy for new pages, and we never had to migrate models or clean up large databases.</p><h3>Downloading Data from a Server</h3><p>There are a few options for retrieving data from the network and the cache or database.</p><p>The simplest is to always retrieve data from the cache and network in parallel. If the cache returns first, call your completion block with the cached data. Then, once the network finishes, call the completion block with the new data. This allows you to contain most of the caching logic in the network layer and all the view controllers need to do is display the data.</p><p>However, this approach will sometimes call the completion block twice. For some apps, this may be problematic, so you could consider only using the cached data if the network is slow. You only display the cached data if the network fails or takes too long to load. I’d recommend setting the timeout for this to be short. Remember that when offline, requests will often timeout after a minute instead of erroring immediately.</p><p>Another solution is to place your cache or database between your view controllers and network. In this ‘reactive’ model, you immediately retrieve models from the database and listen for changes. Once the network request finishes, it edits the database and the view controller automatically updates with the changes. This approach has been <a href="https://www.netguru.co/blog/how-to-design-offline-first-approach-in-mobile-app">well-documented</a>. It’s a simple mental model, but listening to model changes in all view controllers is <a href="https://github.com/realm/realm-cocoa/issues/4818">sometimes not trivial</a> and leads to <a href="https://medium.com/inspace-labs-blog/how-to-observe-changes-on-single-instance-of-nsmanagedobject-f64532f36ef4">a lot of boilerplate code</a>.</p><p>Finally, you can use a database sync solution such as <a href="https://realm.io/products/realm-platform">Realm Platform</a> or <a href="https://firebase.google.com/">Firebase</a>. With these platforms, you host a version of the database on your server and changes are automatically synced to clients in a data-efficient way. These solutions implement a lot of complexity, but this complexity is hidden in a black box and has nontrivial requirements on how you structure your server.</p><h3>Uploading Data</h3><p>When users change data in an application, it’s difficult to decide how this should work in low network connectivity. The simplest way is to show a spinner and wait for the request to finish. You can block the UI and if necessary, alert the user that something failed with a banner or alert. However, this is isn’t the best user experience. I still cannot believe that iMessage won’t allow me to send messages when offline.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*UMrvIZEMAsjyEgBCcu5xuA.jpeg" /><figcaption>iMessage doesn’t work offline? What is this? 2014?!</figcaption></figure><p>A common solution to this problem is to create a queue for offline tasks. If a request fails because of low connectivity, add it to a disk-backed queue and try again when you are connected to the internet. While this sounds simple in theory, in practice, there are a lot of edge cases you need to consider:</p><ol><li>How many times should you retry a request?</li><li>Is the ordering of requests important?</li><li>If a request finally fails after a number of retries, how do I inform the user?</li><li>How do I let the user know that a request is pending and hasn’t yet synced?</li></ol><p>On top of all this, you need to revert the data if an upload fails. Consider the following flow:</p><ol><li>The user likes something on their phone which is <em>offline</em>.</li><li>The user likes the same thing on their laptop which is <em>online</em>.</li><li>The phone connects to the internet, and downloads new data for this item (which says it is liked).</li><li>Next, uploading this like on the phone fails for some reason.</li><li>The phone reverts the item to no longer be liked.</li></ol><p>Notice how the phone ends up in the wrong state! Even worse, since the phone doesn’t know it’s not in the right state, it may not refresh this from the network. When reverting data, you can’t simply take the opposite of an action. You need to revert to the last thing the server told you was correct. This means you now need to store both your current state and the last seen server state.</p><p>These problems are still solvable. When I was at <a href="https://superhuman.com/">Superhuman</a>, we built an architecture we called a ‘modifier queue’ that solved all of these edge cases. You can read more details on this <a href="https://blog.superhuman.com/">on the Superhuman blog</a>.</p><p>Likely for your app, you don’t need to go as far as implementing a modifier queue. Uploading data is difficult, and you should think through which use cases you care most about and concentrate on those being great experiences.</p><h3>Consistency</h3><p>Once you’ve edited your cache or database locally, you may need to update multiple screens in the app. This is a deep topic that is way beyond the scope of this post, but here are a few techniques to consider:</p><ul><li><strong>Listening to Database Changes<br></strong>Most databases offer the ability to listen to models changing. If you’re using a database instead of a cache, this is likely the simplest solution.</li><li><strong>Delegation<br></strong>If a change only affects a couple of view controllers in your app that have a relationship, you can simply use a delegate to propagate the change. Though you can only use this if the change doesn’t appear elsewhere, this is a very simple solution and you shouldn’t overlook it if it just works.</li><li><strong>An Event Bus<br></strong>One of the simplest ways to implement changes to a cache is to use an event bus system to notify all listeners of changes. You simply listen to changes to a certain id and if it changes, reload data from the cache and refresh the view. NSNotificationCenter is the first party solution, but I’d recommend looking at some open source projects that offer a better API as well as typesafe notifications. <a href="https://github.com/100mango/SwiftNotificationCenter">SwiftNotificationCenter</a> and <a href="https://github.com/cesarferreira/SwiftEventBus">SwiftEventBus</a> are two popular examples.</li><li><strong>Rocket Data<br></strong><a href="https://github.com/plivesey/RocketData">Rocket Data</a> manages the consistency for immutable models and is specifically designed to work well with a cache. It simply listens to changes on certain ids and notifies you when a model has changed. It’s a more powerful solution than the event bus and <a href="https://academy.realm.io/posts/slug-keith-smiley-embrace-immutability/">allows you to use immutable models</a>, but also requires more work to set it up. For more information, see <a href="https://academy.realm.io/posts/slug-peter-livesey-managing-consistency-immutable-models/">my talk on Rocket Data</a> or <a href="https://plivesey.github.io/RocketData/">the docs</a>.</li></ul><h3>Combining Techniques</h3><p>I recently added an offline mode to my <a href="https://itunes.apple.com/us/app/chess-tactics-and-lessons/id531275673?mt=8">Chess Tactics App</a>. I had three use cases for offline usage, each with slightly different requirements:</p><ul><li>Users should be able to view all pages in the app offline if they’ve visited them recently.</li><li>Users should be able to explicitly save puzzles to view offline. These should never be evicted.</li><li>The main feature of the app presents a random puzzle to the user curated for their skill level. This should work offline.</li></ul><p>Instead of picking one architecture and trying to fit all of these use cases to it, I decided to pick three different offline techniques!</p><p>For viewing arbitrary pages, I simply added a <a href="https://github.com/pinterest/PINCache">key-value store cache</a> keyed off the URL for the request. I chose a denormalized cache since I didn’t have many submodels in my requests, and submodel consistency isn’t important to my application. Even though I had already coded the entire app, adding this was trivial and only took a couple of hours.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*ahtjtGTer9WxJlp3AIogIQ.jpeg" /><figcaption>Playing puzzles works offline! The rating change is added to a queue and the requests are sent when the user comes back online.</figcaption></figure><p>For saving puzzles, I used a structured database. I never wanted these evicted and there was no chance that the user could save too much data since an individual puzzle is only a few KB. A structured database also allows the flexibility to sort or filter these puzzles in the future.</p><p>For presenting a random puzzle to the user, I also used a database, but instead of using a structured database, I simply used an NSData blob to store the JSON. In the background, the app downloads about 200 puzzles and stores them. If the user is offline, the app selects one randomly (an operation that is difficult with a cache), presents it to the user, and then deletes it. Using a database fit my needs as I could easily control its size. Storing the data as a blob instead of using separate fields allowed me to simplify my code and avoid any additional parsing logic. Contrary to popular belief, storing data as blobs is very fast with a database <a href="https://www.sqlite.org/fasterthanfs.html">as long as the blobs are small</a>.</p><p>When selecting a random puzzle offline, my view controller never used database models directly. Instead, I parsed the data blob into an in memory model before passing it to the view controller. This way, my view controller was completely isolated from any disk storage logic, and I could safely delete these models at any time.</p><p>For uploading data, I implemented a simple queue to upload user rating changes. Since the app is read-heavy, I decided it wasn’t worth it to implement other POST requests. The app simply shows a message saying: ‘your rating will update when you are online.’</p><p>The key point here: you shouldn’t force every feature to use the same offline solution. By combining different techniques, you can provide a better user experience and reduce development time.</p><h3>Conclusion</h3><p>If nothing else, I hope you remember that there are many different solutions for making an app work offline. Don’t just start banging your head against a Core Data implementation immediately because it’s what you’re familiar with; think hard about the problem you’re trying to solve before selecting the best solution.</p><p>For many apps, a cache is a better choice, because it’s a simpler solution. It offers an easy method for eviction, it doesn’t require model migrations, and <a href="https://stackoverflow.com/search?q=core+data+crash">doesn’t crash all the time</a>.</p><p>Regardless of your chosen technology, you also need to consider how you are going to upload changes and keep your app consistent as part of your offline strategy. And finally, you shouldn’t box yourself into just one technology. Often, a combination of different techniques will be the best solution.</p><h3>Additional Tips</h3><p><strong>Where should you save data?</strong></p><p>iOS actually provides a cache directory for storing cache data. However, this directory is <a href="https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html">cleared if the device is running low on space</a>. This is a great thing if it’s actually a cache, but not if you’re relying on this data for basic functionality. You can also put files in the tmp folder for even shorter lived files.</p><p><strong>Offline Detection on iOS is very Flaky</strong></p><p>Apple offers a <a href="https://developer.apple.com/documentation/systemconfiguration/scnetworkreachability-g7d">reachability API</a> that notifies you when connection to the internet changes in some way. However, this API is flaky and you shouldn’t rely on it for infrastructure logic. Internally, it never actually makes network requests. It just tells you when the hardware <em>could</em> connect to the internet. You can use this API for UI to show to the user, but you should never avoid sending a request because of this API — the only way to know if you’re actually able to reach your server is to try the request. Jared Sinclair recently <a href="http://blog.jaredsinclair.com/post/179083065595/til-boy-have-i-been-misusing">wrote a good article on this</a>.</p><p><strong>Normalized Caches Don’t Use Less Data</strong></p><p>As I mentioned earlier, normalized caches don’t necessarily use less data than denormalized caches. Though they don’t duplicate models, there is overhead to store data separately. Consider the following trivial example:</p><pre>// Denormalized data<br>{ id: &#39;parent&#39;, child: { id: &#39;child&#39; }}</pre><pre>// Normalized data<br>{ id: &#39;parent&#39;, child:<strong> &#39;child&#39;</strong> }<br>{ id: <strong>&#39;child&#39;</strong> }</pre><p>Notice how in the second example, the id of the child model is duplicated meaning that the total bytes used by the normalized data in this instance is actually higher. This seems small, but if you have a lot of small, nested models, it really adds up quickly. When working on the LinkedIn app, we found that normalized data took up about 5–10% more space than denormalized data. Because of this, we decided to send denormalized data over the network where size matters.</p><p>Of course, this is dependent on your specific dataset. There’s a tradeoff here, so measure before you decide!</p><p><strong>The Fastest Cache is SQLite!?</strong></p><p>Ironically, the fastest cache I’ve found that’s readily available for iOS development is actually SQLite. You can simply create a model with three fields: id, data, and timestamp. After creating an index on id, lookup and storage is faster than the NSFileManager solution used by many open source solutions. As far as I know, there’s no open source library that implements this API and eviction logic, but if you’re interested in creating one, let me know. I’d be interested in contributing.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2922c9b3bff3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/device-blogs/the-many-offline-options-for-ios-apps-2922c9b3bff3">The Many Offline Options for iOS Apps</a> was originally published in <a href="https://medium.com/device-blogs">Device Blogs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Game Theory of ‘Bullshit’]]></title>
            <link>https://medium.com/game-of-theories/the-game-theory-of-bullshit-aed0872251e8?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/aed0872251e8</guid>
            <category><![CDATA[strategy]]></category>
            <category><![CDATA[mathematics]]></category>
            <category><![CDATA[game-theory]]></category>
            <category><![CDATA[games]]></category>
            <category><![CDATA[card-game]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Wed, 05 Dec 2018 04:13:51 GMT</pubDate>
            <atom:updated>2020-05-22T19:14:24.487Z</atom:updated>
            <content:encoded><![CDATA[<p>In the card game <a href="https://www.wikihow.com/Play-Bullshit">‘Bullshit’</a> (aka ‘Cheat’ or ‘BS’), players can lie about their cards for an advantage. Calling someone’s bluff is risky — if you’re wrong, then you’re punished. Players aren’t incentivised to call bullshit on someone else because it incurs too much personal risk.</p><p>I wanted to dive into the game theory of ‘Bullshit’ so I wrote <a href="https://github.com/plivesey/bs">a short application to simulate the game</a>. I coded several different strategies, played them against each other <em>thousands of times</em>, and worked out the win rate of each strategy.</p><p>You can try playing against the best strategies yourself <a href="https://plivesey.github.io/bs/">here</a>. It’s tough! Hopefully, the rest of this post will help you win.</p><h3>The Rules</h3><p>I picked ‘Bullshit’ for this experiment because the rules were simple and easy to code. There are several other games which employ similar strategies of lying to gain an advantage (such as <a href="https://medium.com/game-of-theories/the-game-theory-of-horse-bc2e547f4c54">Coup</a>), but they are more complex.</p><p>‘Bullshit’ is played with a standard deck of 52 cards. First, you deal out all the cards in the deck. Then, each turn is played as followed:</p><ol><li>Player 1 places any number of cards face down in a stack and claims they are all aces. They must play at least one card, <em>so may be forced to lie</em>.</li><li>Any player can call bullshit if they don’t believe player 1.</li><li>If player 1 lied, then they pick up <em>all</em> the face-down cards, including any that were put down on previous turns. If player 1 told the truth, the bullshit-calling player picks up all the cards. If no-one called bullshit, then play just continues.</li><li>Either way, it’s player 2’s turn and they add cards to the stack claiming they are all 2’s.</li><li>The game continues like this, incrementing the card each turn all the way to the king and then restarting with the ace.</li></ol><p>The game is over when one player gets rid of all their cards. You can see more details on the rules <a href="https://www.wikihow.com/Play-Bullshit">here</a>.</p><h3>Methodology</h3><ol><li>First, I wrote <a href="https://github.com/plivesey/bs">a script</a> to play the game out with certain strategies. Each player has two complementary strategies encoded: a ‘bluffing’ strategy that dictates how they play, and a ‘calling’ strategy that determines when they call bullshit on other players.</li><li>For each strategy, I played it against three other players with random strategies <em>5,000 times</em> and saw how often it won.</li><li>I then <strong>removed the bad strategies</strong> and ran the experiment again so that poor strategies didn’t skew my results.</li></ol><p>The code is all open source: <a href="https://github.com/plivesey/bs">https://github.com/plivesey/bs</a>. Please submit suggestions for other interesting strategies!</p><h3>Bluffing Strategies</h3><p>Here are all the strategies I decided to test. Remember, if a strategy performs poorly, it’ll get removed and I’ll run the test again.</p><p><strong>The Saint — </strong>never lies unless forced. For example, if they have to play an ace, but have no aces, they will be forced to lie.</p><p><strong>The Dabbler — </strong>lies 10% of the time.</p><p><strong>The Coin Flipper — </strong>lies 50% of the time.</p><p><strong>Mr. Pathological — </strong>always lies.</p><p><strong>The Pusher — </strong>always lies when they have a single of one card.</p><p><strong>The Game Theorist — </strong>calculates the expected value of lying based on the chance bullshit is called and only lies if it’s worth it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/355/1*0ly8PkBp1aAT2oA4WutF5g.png" /><figcaption>Naturally, I had high hopes that the game theorist would perform very well.</figcaption></figure><p><strong>The Closer —</strong>doesn’t lie if they can finish the game without doing so. Otherwise, plays as the game theorist would. For example, if they are required to play an ace and have an ace, a five and a nine, then they can guarantee finishing in three turns. In this case, they will never lie. If they had an ace, a two and a five, then they won’t be able to finish so will play as the game theorist would.</p><p><strong>The Comeback Kid — </strong>lies with much higher percentages when losing and never lies when winning.</p><p><strong>The Comeback Closer — </strong>plays like the comeback kid unless they can finish off the game without lying.</p><p><strong>The Pathological Closer — </strong>always lies unless they can finish the game without lying.</p><h3>Calling Strategies</h3><p><strong>The Believer — </strong>never calls bullshit.</p><p><strong>Once in a while — </strong>calls 10% of the time.</p><p><strong>Two-face — </strong>calls 50% of the time.</p><p><strong>The Accountant — </strong>keeps track of how much people lie or tell the truth. Every time someone lies, double the percent chance of calling on them, and every time someone tells the truth, half this chance.</p><p><strong>The Salty One — </strong>calls every so often only on the winning player.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*jBWJLikVhoa8qL6wCF7yeg.jpeg" /><figcaption>The Skeptic (<a href="https://www.magneticmemorymethod.com/skeptics-succeed-memory-techniques/">source</a>)</figcaption></figure><p><strong>The Skeptic — </strong>calculates the chance the player actually has the card they claim and calls if this is lower than 25%.</p><p><strong>Nervous Norbert — </strong>calls the player to the right if they would have to lie on the next turn. This will hopefully clear the discard pile to lessen the risk of needing to lie.</p><p><strong>The Collector — </strong>calls out players if the number of cards played plus the number of the same card that the collector has in their own hand equals four. This means that even if the called-out player is telling the truth, the collector gets four-of-a-kind.</p><p><strong>The Salty Accountant — </strong>plays like the accountant, but calls much more often on the leader than other players.</p><h3>Tactics</h3><p>There are a couple of <a href="https://www.clearpointstrategy.com/strategy-vs-tactics/">tactics</a> that every player uses since it’s always advantageous.</p><p>First, if the current player has no cards remaining, you should always call bullshit on them. Otherwise, you will immediately lose.</p><p>Second, when lying with a card, you always want to lie with your ‘worst card.’ Your ‘worst card’ is the card which you won’t get a chance to play without lying for the longest time. This is <a href="https://github.com/plivesey/bs/blob/master/cl/playFunctions.js#L285">actually trivial to calculate</a>. When this strategy is used against three players that instead pick a random card, the player with this strategy wins 63% of the time!</p><h3>The Initial Results</h3><p>After over 120,000 simulated games, I got some initial results.</p><p>When bluffing, <strong>the more you lied, the more you lost</strong>.</p><ul><li>The Saint (avoid lying) won 51% of games (remember, since there are 4 players, the expected value is 25%).</li><li>Mr. Pathological (lies 50% of the time) only won 2% of games.</li><li>Surprisingly, the Closer (who didn’t lie if they could finish without lying) didn’t do well (9%).</li><li>However, the Comeback Closer (who lied when losing) did much better (43%).</li><li>The Game Theorist (who lied if bullshit wasn’t called much) also didn’t do as well as I expected (28%).</li></ul><p>When deciding when to call people out, <strong>less was more</strong>.</p><ul><li>Players who never called bullshit won 42% of their games.</li><li>Players who called 50% of the time only won 10%.</li><li>I was surprised that the Accountant (who keeps track of how much each player lies) didn’t do well at all. This is probably because <em>you don’t get too many opportunities in one game to see if someone is lying and gathering this information is expensive</em>.</li><li>The Salty One, which only ever called on the leader, also did well — winning 38% of their games.</li></ul><p>You can see all the results <a href="https://docs.google.com/spreadsheets/d/1qDPDnzAv-ltu8CWkTQVq0pak04te96ZgaeVU_-hh9_I">here</a>.</p><h3><strong>The Best of the Best</strong></h3><p>After a couple of rounds removing the worst-performing strategies, I whittled it down to the best four bluffing and four calling strategies.</p><p><strong>The best bluffing strategies were the Saint and the Comeback Closer</strong>.</p><ul><li>The Saint was the better of the two; however, it did poorly (winning only 15%) against the believer (who never calls bullshit).</li><li>The Believer (who never called bullshit) ended up being the best calling strategy (winning 39% of games).</li></ul><p>You can see the full results of round <a href="https://docs.google.com/spreadsheets/d/1qDPDnzAv-ltu8CWkTQVq0pak04te96ZgaeVU_-hh9_I/edit#gid=1271634151">2</a> and <a href="https://docs.google.com/spreadsheets/d/1qDPDnzAv-ltu8CWkTQVq0pak04te96ZgaeVU_-hh9_I/edit#gid=32985099">3 here</a>.</p><p>This caused me to try to work out the best bluffing/calling combination strategies. I tested a <a href="https://docs.google.com/spreadsheets/d/1qDPDnzAv-ltu8CWkTQVq0pak04te96ZgaeVU_-hh9_I/edit#gid=964402966">few different combinations</a> based on the results of my previous runs and found the best combination strategies:</p><ol><li>Comeback Closer + The Believer (only lie when losing and never call)</li><li>The Saint + The Believer (never lie and never call)</li><li>Comeback Closer + The Salty One (only lie when losing and only call on the leader)</li></ol><p>These three strategies in general did well, but had specific strengths and weaknesses when played against each other. This led me to create a ‘metagame’ for the best strategies.</p><h3>The Metagame</h3><p>Surprisingly, Urban Dictionary gives <a href="https://www.urbandictionary.com/define.php?term=metagame">the best definition</a> I could find for the metagame:</p><blockquote>The highest level of strategy in many complex games, metagame refers to any aspect of strategy that involves thinking about what your opponent is thinking you are thinking.</blockquote><p>The best combination strategy is the <strong>Comeback Closer (when bluffing) and Believer (when calling)</strong>. However, if everyone you’re playing against uses this strategy, the best counter is to <strong>always lie and never call bullshit</strong>. Obviously if no one is going to call bullshit, you should always lie. This strategy is best beaten by a combination of the <strong>Comeback Closer and the Salty One (who calls bullshit every so often on the leader)</strong>. Hence, we’re left with the following triangle:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2FS_txsHi_ABAmr7IMEOYg.png" /><figcaption>The ‘Bullshit’ Metagame</figcaption></figure><p>Every experiment so far has also examined playing games in isolation. The metagame is even more important when playing multiple games with the same people. You can try to determine other player’s strategies and pick countering strategies.</p><p>Of course, you should only play the metagame if your opponents are! If your opponents are using random strategies, <strong>you should simply avoid lying and never call. </strong>Against random strategies from above, this combination <strong>wins 69% of games!</strong></p><h3>Conclusions</h3><p>Anecdotally, I’ve never played a game where every other person was using the ‘never call’ strategy. <a href="https://www.psychologytoday.com/us/blog/fulfillment-any-age/201209/why-being-lied-hurts-us-so-much">People hate being lied to</a>. So, psychologically, it’s really difficult not to call bullshit on someone playing a pair with a fake smirk on their face. Outside simple card games, this instinct to hate liars is a good one.</p><p>As we’ve seen here, the best strategy is to never call people out for lying. But, since no one is incentivized to stop other people from lying, this strategy allows others to lie without repercussion — <a href="https://en.wikipedia.org/wiki/Tragedy_of_the_commons">a tragedy of the commons</a>. No one is individually incentivized to stop other people from lying, which allows people to lie. Sadly, in the game ‘Bullshit,’ the heroes who stand up to the liars are often the ones to lose the game.</p><p><strong>Therefore, if you simply avoid lying, never call, and make sure to discard the right card when you’re forced to lie (see the Tactics section above), you’ll have great winning chances.</strong></p><p>Now you know the best way to win, <strong>why don’t you try playing against these strategies? </strong>I wrote a simple web application where you can play against a few of the best strategies: <a href="https://plivesey.github.io/bs/">https://plivesey.github.io/bs/</a>. Let me know if you find ways to consistently win!</p><p><em>Thanks to Brad Svenson, Nate Eborn, Alice Avery, Kyle and Ethan Goldblum for reviewing this post.</em></p><p><em>Kyle is the author of a fantastic game theory blog — </em><a href="https://www.notjustagametheory.com/"><em>https://www.notjustagametheory.com/</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aed0872251e8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-theories/the-game-theory-of-bullshit-aed0872251e8">The Game Theory of ‘Bullshit’</a> was originally published in <a href="https://medium.com/game-of-theories">Game of Theories</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Assertions in Production]]></title>
            <link>https://medium.com/device-blogs/assertions-in-production-e587fef5bfbc?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/e587fef5bfbc</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[quality-assurance]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Fri, 02 Nov 2018 03:45:33 GMT</pubDate>
            <atom:updated>2018-11-14T15:36:12.206Z</atom:updated>
            <content:encoded><![CDATA[<p>Backend engineers know exactly what’s going on with their services. They know their QPS, memory footprint, error rate, and CPU utilization in real time. They even get paged automatically if there’s a critical error so they can respond quickly. Unfortunately, iOS engineers usually only have crash reporting and <em>maybe</em> some product metrics. Usually, we learn about bugs when a user reports it, or worse, when a user posts a bad review. <em>We can do better.</em></p><h3>Reporting Assertions</h3><p>Assertions are conditional checks that ensure that your code is working as expected. Likely, you already have a few in your codebase. They check conditions which should never fail, and if they do, it’s signifies a <em>critical bug</em> in your code. However, assertions are removed in production and have no effect in the real world. On every project I’ve worked on, I’ve added a custom Log type which makes assertions report the error in production. Most crash reporting frameworks have the ability to report non-fatal errors, so implementing this is trivial. Here’s an example using <a href="https://firebase.google.com/docs/crashlytics/">Crashlytics</a>:</p><pre><strong>enum</strong> Log {<br>    <strong>static</strong> <strong>func</strong> assert(<strong>_</strong> condition: <strong>@autoclosure</strong> () -&gt; Bool, <strong>_</strong> message: <strong>@autoclosure</strong> () -&gt; String, file: StaticString = <strong>#file</strong>, line: UInt = <strong>#line</strong>) {<br>    #if DEBUG<br>        Swift.assert(condition(), message(), file: file, line: line)<br>    #else<br>        <strong>if</strong> !condition() {<br>            <strong>let</strong> domain = message()<br>            <strong>let</strong> error = NSError(domain: domain, code: domain.hashValue, userInfo: <strong>nil</strong>)<br>            Crashlytics.sharedInstance().recordError(error)<br>        }<br>    #endif<br>}</pre><pre><strong>    static</strong> <strong>func</strong> assertFailure(<strong>_</strong> message: <strong>@autoclosure</strong> () -&gt; String, file: StaticString = <strong>#file</strong>, line: UInt = <strong>#line</strong>) {<br>        Log.assert(<strong>false</strong>, message, file: file, line: line)<br>    }<br>}</pre><p>In DEBUG, the assert works as it normally does and crashes your app. But in RELEASE builds, it creates an error and reports it to Crashlytics. This will show up like a normal crash but with a non-fatal label. It even includes a stack trace!</p><p>This has been invaluable to responding quickly to bugs. A new non-fatal exception tells me that my code is behaving in an unexpected way. With a stack trace, iOS versions, and the frequency of the problem, I can start trying to reproduce the problem and fix it. Now, I’m responding to bugs <em>before</em> users report them or write bad reviews.</p><h3>Property Tests</h3><p>I’d argue that this use of assertions is a form of <a href="https://techbeacon.com/how-make-your-code-bulletproof-property-testing">property testing</a>. To write a property test:</p><ol><li>You define certain properties which must hold for a certain function.</li><li>Then, you feed the function random input.</li><li>If the properties hold, then the test passes.</li></ol><p>With assertions, instead of writing these tests explicitly, your users generate the input! Your assertions define the ‘properties’ that should always be true. Though your users don’t generate purely random input, the input is often diverse and unexpected. The best part is — these tests don’t require writing any real tests!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*KYLfEYet5XyMkG5NECfUmg.jpeg" /><figcaption>Of course, relying exclusively on testing in this manner isn’t a good idea. But, it does give you some additional confidence that your app is running correctly. <a href="https://medium.com/@aeh.herman/first-steps-in-frontend-testing-with-tdd-bdd-part-ii-a73f529d5914">Source</a></figcaption></figure><p>If you’re interested in property testing, check out <a href="https://github.com/linkedin/LayoutTest-iOS">LayoutTest</a> — a framework which enables you to easily write property tests for your views. The library generates random JSON data and inflates your views with it. Then, you assert properties on your view (such as spacing is correct and no views are overlapping).</p><h3>When to Assert</h3><p>Assertions are underused in most iOS apps and frameworks. Incorrect assumptions about how a function will be used are a common cause of subtle bugs . My general rule is:</p><blockquote>If there is no else statement, there should be an assertion.</blockquote><p>For example:</p><pre>guard let x = x else {<br>    return<br>}</pre><p>What if x is nil? Do we need to show an error to the user? Will some infrastructure silently fail? Often, x should just never be nil. In this case, I’d add an assertion to the else statement:</p><pre>guard let x = x else {<br>    Log.assertFailure(&quot;x is unexpectedly nil&quot;)<br>    return<br>}</pre><p>This is easy to add and also helps document assumptions in the code. Here, my assumption is clear: x should never be nil.</p><p>I also add assertions for:</p><ul><li>Verifying function parameters are correct</li><li>Reading from dictionaries with ‘known keys’ such as NSNotification userInfo</li><li>Log.assert(Thread.isMainThread, &quot;Not on the main thread!&quot;)</li><li>Opening a critical database or file fails</li></ul><h3>Shouldn’t I Let Assertions Crash in Production?</h3><p>I know some of you are thinking: ‘when you hit an assertion, your program is in an unknown state, so it’s better to crash than continue.’ In theory, this may be true, but in practice, I’ve never found it to be valid. It’s often trivial to provide a degraded experience to the user. An empty screen is better than a crash. And since you’ll be able to react quickly to the problem, a fix will be out soon. If you are developing a security framework or banking application, crashing is maybe acceptable. But for most applications, it’s unnecessary to burden your users with your mistakes.</p><h3>But, I Don’t Hit Assertions When Developing</h3><p>You may not hit many assertions when you are developing, but you’d be surprised at what states your users manage to get your app into. You probably don’t test your app on every device, in every network condition, with every operating system, and with every account. I have seen many assertions fire in production which I’ve never seen before in development.</p><p>Are you using a different system to track errors? Do you have other ideas for improving assertions? Let me know in the comments!</p><p><em>Thanks to Sanket Firodiya, Alice Avery, Kamilah Taylor, Melissa Huang, Joe Fabisevich, and Kyle Sherman for helping review this post.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e587fef5bfbc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/device-blogs/assertions-in-production-e587fef5bfbc">Assertions in Production</a> was originally published in <a href="https://medium.com/device-blogs">Device Blogs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Pirates with PhDs]]></title>
            <link>https://medium.com/game-of-theories/pirates-with-phds-3f7d18f92c17?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/3f7d18f92c17</guid>
            <category><![CDATA[behavioral-economics]]></category>
            <category><![CDATA[games]]></category>
            <category><![CDATA[mathematics]]></category>
            <category><![CDATA[game-theory]]></category>
            <category><![CDATA[logic]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Tue, 02 Oct 2018 21:54:10 GMT</pubDate>
            <atom:updated>2018-10-06T00:32:25.839Z</atom:updated>
            <content:encoded><![CDATA[<p>This post is about one of my favorite brainteasers. I love it for two reasons:</p><ol><li>It has a surprising but understandable solution.</li><li>It makes you consider what it means to be rational and logical.</li></ol><p>The puzzle has a logical solution, but wanted to test whether actual humans would come to that solution by <em>simulating the puzzle in real life with seven participants</em>. But first, if you haven’t heard it before, you should spend some time to solve it yourself.</p><h3>The Puzzle</h3><p>Seven pirates have 100 gold coins to split amongst themselves. They have chosen an interesting way of splitting the pot.</p><ol><li>The first pirate gives a proposal for how many pieces of gold each pirate will receive.</li><li>Then, everyone (including the first pirate) votes yes or no on this proposal.</li><li>If 50% or more of the pirates approve the proposal, it’s accepted and the process is over.</li><li>Otherwise, pirate 1 is killed and pirate 2 proposes a new way of splitting the gold and pirates 2–6 vote on the new proposal.</li><li>If the vote fails again, pirate 2 is killed and pirate 3 proposes a solution. It continues like this until a vote passes.</li></ol><p>You can assume:</p><ol><li>These are no normal pirates! Not only do they plunder the high seas, but they also have PhDs in mathematics and you can expect them to behave hyper rationally.</li><li>Each pirate wants to stay alive and get as much gold as they can. They have no ethical concerns about killing other pirates.</li></ol><p>How should pirate 1 propose splitting the gold to maximize their gold?</p><p><a href="https://gist.github.com/plivesey/42ccf9ac4f2fa8659d1a08a5ee3921f5">Hint #1</a><br><a href="https://gist.github.com/plivesey/0b4bea28cd7c13f0d1fb9208fa0a3792">Hint #2</a><br><a href="https://gist.github.com/plivesey/79c764c63f723df923be194ed0755625">Hint #3</a></p><p>The answer is below this awesome gif of a cat pirate.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/732/1*2g_jl_xi-u1adKhf-RA2oQ.gif" /></figure><h3>Solution</h3><p>Pirate 1 should propose giving <em>1 gold</em> to pirates 3, 5, and 7 and keep <em>97 gold</em> for themselves. This may surprise you, so let me explain.</p><p>First, let’s look at the simplest version of the problem. If there were just two pirates left (#6 and #7), then pirate 6 would just keep 100 gold for themselves. Since there are only two votes, pirate 7 cannot override this decision. So, pirate 7 knows that if it gets to this point, then they will get nothing.</p><p>If there are three pirates remaining, pirate 5 could offer pirate 7 just one gold for their vote. Since one gold is better than none, pirate 7 will vote yes, and the vote would pass 2 against 1. So, if it gets to three pirates, it will be split 99–0–1. We can continue this pattern for four pirates. Pirate 4 only needs one vote to get 50% of the votes, so can offer just 1 gold to pirate 6. Pirate 6 would accept since they would get nothing if it got down to three pirates. If we follow this logic all the way to seven pirates we get:</p><p>2 pirates: 100–0<br>3 pirates: 99–0–1<br>4 pirates: 99–0–1–0<br>5 pirates: 98–0–1–0–1<br>6 pirates: 98–0–1–0–1–0<br>7 pirates: 97–0–1–0–1–0–1</p><p>This solution seems too imbalanced to be correct, but it’s the logical conclusion of all pirates acting rationally and trying to maximize their own gold. There’s no way for pirates 2–7 to get any more gold alone by voting a different way. In game theory, this is known as a <a href="https://en.wikipedia.org/wiki/Nash_equilibrium">Nash Equilibrium</a> — no player has anything to gain by changing strategies. Changing the results would rely on collusion between two or more pirates (and pirates aren’t the most trustworthy bunch</p><h3><strong>The Experiment</strong></h3><p>The correct answer is logical, but perhaps real humans wouldn’t reach the same conclusion. So, I got seven friends together and asked them to do the puzzle in real life. They played the game three times:</p><ol><li>In the first game, there would be public discussion, but no private messaging.</li><li>In the second game, there would be no public discussion or private messaging — only voting.</li><li>In the third game, players could private message each other.</li></ol><p>Everyone playing the game <em>knew and understood the correct answer</em> to the problem. They were all smart and rational people playing to win. The rules were the same as the riddle (except of course, we didn’t kill anyone if their vote failed; they just didn’t get any gold).</p><h3><strong>Hypothesis</strong></h3><p>As I mentioned earlier, the decision to vote yes or no by each player reaches a <a href="https://en.wikipedia.org/wiki/Nash_equilibrium">Nash Equilibrium</a>, so no player is incentivized to vote differently. However, pirate 1’s strategy doesn’t produce a <em>stable</em> Nash Equilibrium. The equilibrium is stable if it is resilient to small mistakes. In this case, if pirate 3, 5 or 7 make a mistake and vote the wrong way, it has dramatic implications for pirate 1. So, if I were pirate 1, I’d mitigate this risk by:</p><ol><li>Giving an additional pirate some gold</li><li>Giving each pirate a bit more than 1 gold (around 5 should do it)</li></ol><p>The less discussion there is, the more power the first pirate will have. So in round 2, I thought that pirate 1 could probably get away with taking 97 gold. But in rounds 1 and 3, I thought that they’d only get away with about 80 gold and splitting the rest amongst four other pirates. Regardless, I thought pirate 1&#39;s vote would always pass, they would take the majority of the gold, and the games would be short.</p><p>Oh, how I was wrong…</p><h3><strong>The Games</strong></h3><p>In game 1, pirate 1 quickly proposed a vote that exactly followed the puzzle before too much could be discussed (keeping 97 gold for themselves). And then, <strong><em>everyone voted no</em></strong>.</p><p>Suddenly, the game had completely changed. Now, instead of the proposing pirate having all the power, they had all the fear. After pirate 1’s vote failed, pirate 2 ended up successfully proposing a split which only gave them 30 gold. They were now convinced that the equilibrium was extremely unstable and needed to give significant gold to three other pirates to get just two votes.</p><p>In game 2, there was no discussion allowed. Pirate 1 clearly felt the <em>fear</em> of being in the first position and proposed an insane 10 gold for themselves and 15 gold to each other pirate. In this case, pirate 1 is actually getting <em>less</em> gold than the other players. I thought they could have easily asked for more, but the vote only passed with the <em>minimum required four votes</em>.</p><p>In game 3, there was a public discussion as well as private messaging. This game was nuts and I must leave out a lot for succinctness. First, pirate 1 proposed a 37/21/21/21 split which failed. The player who turned down 21 gold ended up getting nothing at the end of the game, and hence, the theme of the last game was hubris. In several cases, players backchanelled with other players and voted no thinking they’d end up with a better deal. Then, they’d see their plans backfire and end up with nothing.</p><p>In the second round, pirate 5 was granted 30 gold, but had an offer for 31 gold if they voted no. Again, hubris took over and they voted no, only to end up with nothing at the end of the game. The game finished in the 4th round with a 60/40 split between pirates 4 and 7.</p><h3><strong>Conclusions</strong></h3><p>In all three games, pirate 1 never got the 97 gold the brainteaser promised. In fact, it was the worst position to be in (two deaths and 10 gold). Fear and hubris quickly overtook the cold logic of the puzzle to produce a dynamic game in which every player thought they had a shot at winning more. The number of pirates also made reasoning through strategy difficult. With 3–4 players, the optimal strategy quickly becomes clearer, but with seven pirates, it seemed like anything could happen. Hence, the game relied much more on short-term tactics, fear, hubris and a bit of luck.</p><p>The theoretical solution to the problem is <em>logical</em>, but are the pirates really behaving <em>rationally</em>? The problem assumes that the pirates are emotionless, greedy algorithms who grab as much gold as they can. But people may be willing to take a risk if they don’t value a single gold coin highly. If the value of a coin is low, then the difference between 1 coin and 0 coins may be inconsequential. In this case, pirates may be tempted to vote no on the first round to see if other pirates feel similarly.</p><p>The theoretical pirates also appear heartless and have no concept of fairness. In the real life experiment, players voted no and forfeited gold to punish an ‘unfair’ result. This persuaded other pirates to ‘behave’ and propose more even splits. This bias toward fair outcomes suggests that aren’t always happy with the logical, mathematical solution. Sometimes, the <em>optimal solution</em> is not a <em>human solution</em>.</p><p>Thanks to the seven pirates — Brad Svenson, Hari Arul, Camilo Cabrera, Jason Zhang, Charles Huyi, Patrick Costello, and Dawson Zhou.</p><p>The game was a lot of fun to play — let me know if you try the game yourself!</p><p>Thanks to Alice Avery And Dawson Zhou for helping me review this post.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3f7d18f92c17" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-theories/pirates-with-phds-3f7d18f92c17">Pirates with PhDs</a> was originally published in <a href="https://medium.com/game-of-theories">Game of Theories</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Steps to a Better Onboarding Experience]]></title>
            <link>https://medium.com/device-blogs/5-steps-to-a-better-onboarding-experience-11945f0b8abf?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/11945f0b8abf</guid>
            <category><![CDATA[onboarding]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[ux]]></category>
            <category><![CDATA[chess]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Mon, 17 Sep 2018 16:21:00 GMT</pubDate>
            <atom:updated>2018-09-21T16:36:06.376Z</atom:updated>
            <content:encoded><![CDATA[<p>Likely, your app’s onboarding experience isn’t very good. This isn’t because your product isn’t well designed or easy to learn; it’s because building successful onboarding experiences is just <em>hard</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/656/1*bu6kKL8eOTgPBetyIsFuhg.jpeg" /><figcaption>todayfm.com</figcaption></figure><p>A couple of months ago, my <a href="https://itunes.apple.com/us/app/chess-tactics-and-lessons/id531275673">chess puzzle app</a> was struggling to retain new users. I loved the app, and many of my users did too, but, most people who downloaded the app wouldn’t use it more than once. So, I decided to build an onboarding experience for all the lost users.</p><p>Today’s users are <a href="https://uxplanet.org/why-todays-app-users-are-the-most-complicated-ever-4bd18186147">more discerning than ever</a>, <a href="https://www.statista.com/statistics/268251/number-of-apps-in-the-itunes-app-store-since-2008/">have more options</a>, and have <a href="https://in.reuters.com/article/apps-attention-span/when-it-comes-to-apps-consumers-have-shorter-attention-spans-idINDEE97J0DU20130820">shorter attention spans</a>. When you look at your product, you may see a useful, beautiful, fun app which is great at solving a specific problem or need. But when new users see your product, they see a <a href="https://justuxdesign.com/blog/the-paradox-of-choice-more-isn-t-always-better">menu with too many options</a>, a login screen trying to steal their email address, and a learning hurdle they need to overcome.</p><p>I followed five steps which got me to an onboarding experience I was proud of:</p><ol><li>Dissect your current onboarding</li><li>Make your users successful ASAP</li><li>Bucket your users</li><li>Test it on real users</li><li>Measure your success</li></ol><h3><strong>1. Tear it apart</strong></h3><p>It’s hard to critique your own work, but it’s a valuable skill to foster. I was inspired to take this step seriously by <a href="https://www.useronboard.com/">useronboard.com</a>. The site has done incredible teardowns of many famous products and does a fantastic job showing what works and doesn’t work when onboarding new users. I’d highly recommend going through several of their slideshows before taking a look at your own product.</p><p>So, here is my teardown of my old app with all its flaws. I hope you find it brutal enough.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.slideshare.net%2Fslideshow%2Fembed_code%2Fkey%2Fzk3lapbW0AoFXd&amp;url=https%3A%2F%2Fwww.slideshare.net%2FPeterLivesey1%2Fchess-tactics-lessons-onboarding-analysis&amp;image=https%3A%2F%2Fcdn.slidesharecdn.com%2Fss_thumbnails%2Fchesstacticsonboarding-180905173558-thumbnail-4.jpg%3Fcb%3D1536169096&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=slideshare" width="600" height="500" frameborder="0" scrolling="no"><a href="https://medium.com/media/36fde73132b77678dcea7fa5b1f62ba6/href">https://medium.com/media/36fde73132b77678dcea7fa5b1f62ba6/href</a></iframe><p>There’s obviously a lot to improve, but the top things I decided to fix were:</p><ol><li>Persuade the user the app is worth their time before asking them to sign up.</li><li>Set up each user for success, not failure.</li><li>Minimize choice when users first use the product.</li></ol><h3><strong>2. </strong>Make your users successful ASAP</h3><p>Great products aren’t just powerful; they make people <em>feel</em> powerful. Your product should <a href="https://medium.com/building-winning-products/kathy-sierra-on-designing-for-badass-ba92cd5fad96">transform your user into a better version of themselves</a>. This could be making them more productive, more informed, or simply happier. You need to identify the <strong>earliest moment that people feel this emotion</strong>.</p><p>For us, this action was completing a difficult puzzle correctly. Chess is a hard game, so this is no easy feat. But when users overcome this challenge, they realize they’ve become something new — a smarter chess player. This transformation will persuade them to keep using the app.</p><p>Currently, the app requires users to sign in before even attempting a puzzle. Instead of this, I rewrote how login worked to allow people to play puzzles without signing up. I <strong>only ask them to sign up after they’ve successfully completed a puzzle</strong>. But, the order of these actions is only half the problem. As I said, chess is a difficult game, and many users aren’t yet capable of completing a difficult puzzle. If the app gave them a difficult puzzle immediately, they’d be set up to fail.</p><h3><strong>3. Bucket users</strong></h3><p>When an experienced player comes to the app, they want to be challenged. But, if the first puzzle the app gives users is too difficult, beginners will fail. So, I had to design different experiences for beginners and experts. This is the first screen for a fresh install:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*8-5VeGkUMadCNMvP2D1lVg.png" /><figcaption>First launch screen</figcaption></figure><p>A couple of things to note:</p><ol><li>This screen has only three options so the user won’t be overwhelmed for choice.</li><li>Users are often nervous about picking wrong and then having to restart. The help text at the bottom should help these users realize that this decision won’t ruin their experience if they pick slightly wrong.</li></ol><p>Likely, your user cohorts will be different. If you’re a music discovery app, you might bucket users into those who are looking for specific music and users who want to explore new music. For a reading app, you may split your users into fiction readers, nonfiction readers or other genres. Just make sure you don’t make the mistake that <a href="https://support.apple.com/en-us/HT204842">Apple Music</a> and many other apps make which overload their users with options. <strong>People are way more willing to enhance their profile <em>after</em> they see value than before.</strong> You should bucket them just enough to get them to that key experience you’ve identified.</p><p>If a user is a beginner, they start with some interactive lessons which teach them how to solve chess puzzles. If the user is advanced, they go straight into tough and interesting puzzles.</p><h3><strong>4. User Testing</strong></h3><p>Once you’ve built a first version of your onboarding, you need to test it on some real people! You’ll be shocked at how difficult people find things which you think are easy. The best way to do this testing is in person. You won’t understand how people are using your app unless you actually watch them. Find some friends who haven’t used the app, sit down with them and ask them to start using the app. Likely, they will quickly ask you questions on how things work or what they should be doing. Resist the urge to help them! Instead, simply reply with more questions like:</p><p>“What would you do if I weren’t here?”</p><p>“Do you see a way of answering that with the product?”</p><p>Every time they ask you a question, it shows a weakness in your onboarding flow. New users have no loyalty and will quickly revert to using other apps at the first sign of trouble. Candy crush is just a few taps away and you only have <a href="http://fortune.com/2016/05/19/app-economy/">one chance to convert each person</a>. On one of the user tests I did, I wrote down twenty-nine places the user could have dropped out! Each problem was just a small fix such as writing clearer copy or adding a tooltip.</p><h3><strong>5. Measure success</strong></h3><p>When you release your new experience, you’ll want to see how much better you’re app is doing. You should identify a few metrics which you expect to improve after the release. For my app, I wanted to improve 1-day and 7-day churn as well as have more users attempt at least one puzzle. You don’t need to overdo it here and track every user action as they onboard. Just track a few key flows and try to find where users drop off.</p><p>We’ve only just released the new update, so I don’t have much data yet. Early results suggest that <strong>day 1 retention has approximately doubled</strong>. I’ll update this post once we have more to share!</p><p><em>Update:</em> It’s been a little over two weeks since we released the new version and day 1 retention has remained bullish (increasing by about 2.5x). However, day 7 retention has only increased by about 50%. This is still a great improvement, but I think I can do even better. Since most of my work concentrated on the first few days, this isn’t that surprising. Next, I should look at keeping the user engaged a week or more after they’ve used the product.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*FxDGcCN-VdZXF5uhvZ--eA.png" /><figcaption>Success! The sooner users get here, the better.</figcaption></figure><h3><strong>Try it for yourself</strong></h3><p>If you’re looking for ideas, want to learn something new, or just have some fun, check out what we’ve done. You can download the <a href="https://itunes.apple.com/us/app/chess-tactics-and-lessons/id531275673">new Chess Tactics &amp; Lessons on the App Store</a>, and let us know what you think of the onboarding process in the comments.</p><p><em>Thanks to Alice Avery, Nick Snyder, Islam Sharabash, Judy Logan, Ryan Blunden, and Joe Kramer for your help on this post.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=11945f0b8abf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/device-blogs/5-steps-to-a-better-onboarding-experience-11945f0b8abf">5 Steps to a Better Onboarding Experience</a> was originally published in <a href="https://medium.com/device-blogs">Device Blogs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Game Theory of HORSE]]></title>
            <link>https://medium.com/game-of-theories/the-game-theory-of-horse-bc2e547f4c54?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/bc2e547f4c54</guid>
            <category><![CDATA[math]]></category>
            <category><![CDATA[probability]]></category>
            <category><![CDATA[basketball]]></category>
            <category><![CDATA[strategy]]></category>
            <category><![CDATA[game-theory]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Sun, 05 Aug 2018 13:13:29 GMT</pubDate>
            <atom:updated>2018-08-05T13:13:29.204Z</atom:updated>
            <content:encoded><![CDATA[<p>HORSE may seem like a simple backyard game, but, surprisingly, there is a strategy which improves your chance of winning — and it probably isn’t what you’d expect.</p><p>HORSE is a popular basketball game where players take turns attempting the same shot. With two players, the game works like this:</p><ol><li>Player A attempts any basketball shot.</li><li>If they make it, then player B has to make the exact same shot. Otherwise, it’s player B’s possession.</li><li>If player B misses, they acquire a letter. Either way, Player A gets to shoot again.</li><li>Letters are acquired in order: H-O-R-S-E. Once a player acquires all five letters, they are a horse and lose the game because horses can’t play basketball.</li></ol><p>It’s a simple game, but strategy isn’t well understood by most players. I wanted to dig into the metagame of HORSE and work out if there are optimal ways to play using game theory, strategy, and a little math. Of course, being better at shooting will always be advantageous, but let’s take a look at the decisions you <em>can</em> make.</p><h4>The Setup</h4><p>There’s only one element of strategy in the game — shot selection. You could take a free throw, a layup, or a left-handed, eyes-closed, 3-pointer skyhook. Conventional wisdom is to take a shot that you’re good at but that your opponent will probably miss. For instance, Steph Curry can just attempt three-pointers and watch his opponent miss.</p><p>For a given shot, there’s a probability that you make the shot and a probability that your opponent makes the shot. Given these values, we can calculate the <a href="http://www.statisticshowto.com/probability-and-statistics/expected-value/">expected value</a> of the number of letters your opponent will get on your possession (or the average number of points on each possession if you were to play it many times). The best strategy maximizes this expected value. <em>Remember, in HORSE, a possession lasts until you miss</em>. So, you could have multiple shots per possession.</p><pre>E = expected number of letters your opponent gets on your possession<br>p = probability that you make the shot you select<br>o = probability that your opponent makes the same shot</pre><p>In order to give your opponent a letter, you need to make a shot <em>and</em> your opponent needs to miss their shot. The probability of this is:</p><pre>p(1 - o)</pre><p>This is also the expected value of letters your opponent gets on <em>one</em> shot. But, if you make it, <em>then you get to shoot again</em>. The expected value of future shots is the probability you make the first shot multiplied by the expected number of letters your opponent gets on a possession (since if you make your shot, you’re in the same situation as if you just started).</p><pre>p * E</pre><p>To get the expected value of letters your opponent gets in an <em>entire possession</em> you just add the expected value of the first shot and the expected value of future shots.</p><pre>E = p(1 — o) + p * E</pre><p>Then, we can solve for E:</p><pre>E — p * E = p(1 — o)</pre><pre>(1 — p)E = p(1 — o)</pre><pre><strong>E = p(1 — o) / (1 — p)</strong></pre><p>Now, we have a formula for the expected value of a possession based on the chance you can make a shot and the chance your opponent makes the same shot.</p><h4><strong>A Basic Scenario</strong></h4><p>Let’s assume both players have the same skill and ability for all shots. So, if Player A has a 40% chance of making a shot, then Player B also has a 40% chance of making that same shot. This is a big assumption and is never true in practice, but it’ll reveal whether shot selection makes a difference. We’ll look at some more complex scenarios later.</p><p>Player B’s strategy is to repeatedly take shots with a 50% make rate. Let’s look at the expected value of that strategy.</p><pre>E = p(1 — o) / (1 — p)<br>Solving for p = 0.5 and o = 0.5</pre><pre>E = (0.5)(1 – 0.5) / (1 – 0.5)</pre><pre>E = 0.5</pre><p>Since the expected value is 0.5, on every turn for Player B, Player A will get on average half a letter. This means Player A is likely to get H-O-R-S-E in 10 turns.</p><p><strong>Optimizing for Player A</strong></p><p>Let’s generalize this for any shot and try to find the optimal strategy. In this scenario, p = o (the probability you each make a shot is equal), so we can just substitute it in the formula:</p><pre>E = p(1 — o) / (1 — p)</pre><pre>E = p(1 — p) / (1 — p)</pre><pre><strong>E = p</strong></pre><p>The expected value of a certain shot is equal to the probability of making that shot. To maximize E, you just need to maximize p. <strong>This means you should always choose the easiest shot you can! </strong>Just keep taking layups and hope your opponent misses before you do.</p><p>If you keep taking a shot that has a 99% chance of making your shot, the expected number of letters your opponent will get per possession is 0.99 which means your opponent will lose in about 5 possessions. So this strategy is twice as good as selecting a 50% shot. <strong>Just keep attempting layups, and you will have an optimal strategy.</strong></p><h4><strong>What if you are much better at shooting three-pointers?</strong></h4><p>The previous scenario assumed equal abilities, which, of course, is never true. Let’s assume that you’re playing against Steph Curry who dominates three-pointers. Steph has a 40% success rate, and you have 10%. You both have a 99% chance of making a layup (probably low for Steph, but let’s go with it). Since Steph is 4x more likely to make a three-pointer, surely that’s a better shot to take, right? We know that the expected value for the layup is 0.99. The expected value for the three-pointer:</p><pre>E = p(1 — o) / (1 — p)</pre><pre>E = (0.4)(1 – 0.1)/(1 – 0.4)</pre><pre>E = 0.6</pre><p>If Steph Curry were to shoot three-pointers, you’d get on average 0.6 letters per turn. But, he’d be getting 0.99 letters per turn! So, even if you have a much better chance (4x) of making that three, the layup strategy is still better! It turns out that <strong>keeping possession (making your shot and shooting again) is much more important than ensuring a better shot than your opponent</strong>.</p><h4><strong>So wait…did I just ruin HORSE?</strong></h4><p>Personally, I was disappointed by my results. It looks like I’ve reduced a great game to a layup competition which stretches on for hours. So, I feel obligated to try to fix the game. I have three suggestions:</p><p><em>1. Don’t allow the player to keep the ball if they make their shot</em></p><p>The main problem is that the player with the ball keeps the ball if they make it. Let’s take a look at what would happen if we remove this rule. This means the expected value is simply:</p><pre>E = p(1 — o)</pre><p>If you have two identical players, then this simplifies to p(1 — p) and the graph for p vs E looks like this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RnWuvp51RJ18jxgmhTyqcw.png" /></figure><p>E is maximized at 0.25 when p is 0.5, so the optimal strategy is to take shots with a 50% make-rate. That’s already sounding like a better game. If you’re four times more likely to make a three-pointer (like Steph Curry in our previous example), then E becomes 0.36. This better outcome would reward being a better three-point shooter. With this rule change, we’re much closer to making the strategy result in a fun game. But sadly, low percentage shots are still not a good idea — meaning your patented 360º, underhand, off-the-backboard, ten-foot jumper is still far from optimal.</p><p><em>2. Set different point limits for different shots</em></p><p>If you assign more letters to harder shots, there would be a higher incentive to try shooting them. For instance, if you make three-pointers worth double (two letters instead of one), then the expected value from our earlier example becomes 2 * 0.6 = 1.2, making it slightly better than the layup strategy where the expected value is 0.99. You could also ban easy shots (requiring a minimum distance).</p><p>However, these approaches are not practical. Assigning a letter value to every shot is difficult and subjective. Also, some shots close to the basket are difficult even if they’re close (e.g. shots from behind the backboard).</p><p><em>3. Just play the game</em></p><p>Maybe the best solution is to ignore everything in this article and <em>just play the game</em>. Is it really that important to win HORSE? Maybe you should play for the beauty of the game. Maybe you shouldn’t subject your friends to 200 layups in a row. You <em>could</em> optimize by taking the easiest shot every time, but maybe the real goal is to become the legend who makes that behind-the-back, eyes-closed, half-court shot.</p><p>If you have any better ideas for how to fix HORSE, please let me know in the comments.</p><p><em>Thanks to Alice Avery, Brad Svenson, Hari Arul, Ranee Bhutani, and Alastair Livesey for your feedback and comments.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bc2e547f4c54" width="1" height="1" alt=""><hr><p><a href="https://medium.com/game-of-theories/the-game-theory-of-horse-bc2e547f4c54">The Game Theory of HORSE</a> was originally published in <a href="https://medium.com/game-of-theories">Game of Theories</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Advanced Swift debugging for UIKit]]></title>
            <link>https://medium.com/superhuman-co/advanced-swift-debugging-for-uikit-e154d1c28aaf?source=rss-30f43bddcaef------2</link>
            <guid isPermaLink="false">https://medium.com/p/e154d1c28aaf</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[objective-c]]></category>
            <category><![CDATA[iphone]]></category>
            <dc:creator><![CDATA[Peter Livesey]]></dc:creator>
            <pubDate>Fri, 04 May 2018 16:34:14 GMT</pubDate>
            <atom:updated>2019-10-11T05:02:06.709Z</atom:updated>
            <content:encoded><![CDATA[<p><em>At </em><a href="https://superhuman.com/?utm_source=medium&amp;utm_medium=blog&amp;utm_campaign=advanced-swift-debugging"><em>Superhuman</em></a><em>, we’re building the fastest email experience in the world.</em></p><p><em>This post describes several techniques to debug closed source libraries such as UIKit.</em></p><p>As we’ve pushed iOS to its limits, we’ve found some inscrutable runtime bugs. In order to solve these, we’ve had to dive into the deepest internals of UIKit.</p><p>Since UIKit is closed source, we can’t place breakpoints or view the code. However, as we’ll see, nothing in Objective-C is really private.</p><p>In this post, we’ll cover:</p><ul><li>Reading private variables</li><li>Swizzling to see property changes</li><li>Watching memory to observe instance variable changes</li></ul><p>Most of these examples are based on UIKit, but the techniques apply to any private Objective-C framework.</p><h3>Reading Private Variables</h3><p><strong>Look at the Runtime Headers</strong></p><p>The UIKit source code is not public, but we can read its runtime headers (.h files) to see method and variable names. The method names hint at their implementation, and importantly allow us to call them.</p><p>A few sites index the runtime headers. For example <a href="http://developer.limneos.net/?ios=11.1.2&amp;framework=UIKit.framework&amp;header=UITableView.h">limneos.net</a>, which can also search specific iOS versions.</p><p>If we are having trouble with a certain property or method in a class, we can search the header file for related methods.</p><p><strong>Calling Private Methods</strong></p><p>Once we find an interesting private method, it’s useful to print the result from the debugger. For instance UITableView has a private method: -(id)_delegateActual. We can’t run this in Swift, because Swift does not allow the calling of private methods:</p><pre><strong>(lldb) po tableView._delegateActual()</strong></pre><pre>error: &lt;EXPR&gt;:3:1: error: value of type &#39;UITableView&#39; has no member &#39;_delegateActual&#39;</pre><p>However, in Objective-C, we can run arbitrary selectors on any object. We can get the pointer for the object, and then run an expression in Objective-C:</p><pre><strong>(lldb) po tableView<br></strong>&lt;UITableView: 0x7ff960053200; frame = (0 0; 375 812); clipsToBounds = YES; gestureRecognizers = &lt;NSArray: 0x604000249e40&gt;; layer = &lt;CALayer: 0x60400003f880&gt;; contentOffset: {0, 61}; contentSize: {375, 1320}; adjustedContentInset: {88, 0, 34, 0}&gt;</pre><pre><strong>(lldb) e -l objc -O -- [0x7ff960053200 _delegateActual]<br></strong>&lt;TableViewExperiments.ViewController: 0x7ff95ec1d7d0&gt;</pre><p>In this example:</p><ul><li>e is short for expression which runs code and prints out the result</li><li>-l sets the language to Objective-C</li><li>-O specifies that this is an object, so the command should dereference the pointer before printing it out</li></ul><p>If you’re printing a primitive, simply omit -O.</p><p>(e -l is useful in other contexts too. e -l Swift allows you to run Swift code even when your stack frame is Objective-C.)</p><p><strong>Reading Private Instance Variables</strong></p><p>Let’s say we find a private instance variable that we want to read. In modern Objective-C, properties are much more common than instance variables; we can simply use the above technique to run the private getter or setter methods backing the property. However, in UIKit, instance variables without properties are common and so are much harder to debug.</p><p>Recently, we were interested in the _firstResponderIndexPath property on UITableView. This property appears to be set whenever a cell in UITableView becomes the first responder. To read this variable, we can’t use the above trick because _firstResponderIndexPath is an instance variable:</p><pre><strong>(lldb) e -l objc -O -- [0x7ff960053200 _firstResponderIndexPath]</strong></pre><pre>error: Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector.</pre><pre>The process has been returned to the state before expression evaluation.</pre><p>However, nothing is really private in Objective-C. We can use the runtime to access any instance variable, even if it is private. First, we need to query the class for the Ivar object. Then we can query the instance for the value of this instance variable:</p><pre><strong>(lldb) po object_getIvar(tableView, class_getInstanceVariable(UITableView.self, &quot;_firstResponderIndexPath&quot;)!)!</strong></pre><pre>&lt;NSIndexPath: 0xc000000000600016&gt; {length = 2, path = 0–3}</pre><h3>Swizzling</h3><p>It is useful to call and read private methods, but it is often more useful to see when these values change. Swizzling allows us to add breakpoints, examine the stack, and get clues on how features are implemented.</p><p>We want to know when a property on an object is changing. The easiest way to do this is to swizzle the setter. Swizzling is an Objective-C runtime technique to exchange method implementations. We replace the existing method with a new method, print the new value, and then call the old method. We effectively insert some debug code between the call site and the actual implementation of the method. The confusing part is this: in order to call the old method, we must call the new method’s signature, since we’ve exchanged their names. It looks like this:</p><pre>extension UIScrollView {<br>    class func swizzleZoomScale() {<br>        let originalMethod = class_getInstanceMethod(self,<br>            #selector(setter: minimumZoomScale))<br>        let swizzledMethod = class_getInstanceMethod(self,<br>            #selector(swizzle_setMinimumZoomScale(_:)))<br>        method_exchangeImplementations(originalMethod!,<br>            swizzledMethod!)<br>    }</pre><pre>    @objc dynamic func swizzle_setMinimumZoomScale(_ scale: CGFloat) {<br>        print(&quot;new value: \(scale)&quot;)</pre><pre>        // It looks like we&#39;re entering an infinite loop,<br>        // but exchangeImplementations has switched the method’s <br>        // names. So this method signature now maps to<br>        // the original minimumZoomScale implementation</pre><pre>        self.swizzle_setMinimumZoomScale(scale)<br>    }<br>}</pre><p>In this case, we wanted to know when the minimum zoom scale changed. First, we call swizzleZoomScale() exactly once (for example, from UIApplicationDelegate). Then, we put a break point in the swizzle_setMinimumZoomScale. Whenever setMinimumZoomScale is called, the breakpoint will hit. We will then have a full stack trace to examine where and why the zoom scale changed.</p><p><strong>Swizzling Private Methods</strong></p><p>If we are trying to swizzle a private method, the above code won’t work; it cannot find the selector we want to replace. There’s an easy fix though. We just create an Objective-C category on the object and add it to the interface. We don’t need to implement it; we just need to let the compiler know it exists.</p><pre>@interface UITableView (Private)</pre><pre>- (void)_applePrivateMethod;</pre><pre>@end</pre><p>With this, we’ll be able to swizzle _applePrivateMethod.</p><h3>Watching Memory</h3><p>If we want to know when a property changes, we can simply swizzle the setter. However, many UIKit variables are not backed by properties but are instead set directly. Swizzling won’t help in this case; we must watch memory directly.</p><p>We can listen to any variable with the watchpoint command in lldb:</p><pre><strong>(lldb) watchpoint set variable self.counter</strong></pre><p>This will hit a breakpoint whenever counter changes value. However, this doesn’t work for private instance variables, since self.counter would not be accessible. To get around this, we can find the memory address of the instance variable.</p><p>Consider again the private instance variable _firstResponderIndexPath. This is set when a cell in UITableView becomes the first responder. First, we ensure the value is not nil, and then we print it out:</p><pre><strong>(lldb) po tableView<br></strong>&lt;UITableView: 0x7fefb482da00; frame = (0 0; 375 812); clipsToBounds = YES; gestureRecognizers = &lt;NSArray: 0x604000249e40&gt;; layer = &lt;CALayer: 0x60400003f880&gt;; contentOffset: {0, 61}; contentSize: {375, 1320}; adjustedContentInset: {88, 0, 34, 0}&gt;</pre><pre><strong>(lldb) po object_getIvar(tableView, class_getInstanceVariable(UITableView.self, &quot;_firstResponderIndexPath&quot;)!)!</strong></pre><pre>&lt;NSIndexPath: 0xc000000000400016&gt; {length = 2, path = 0 - 3}</pre><p>This is useful, but it’s not the memory we want to watch. To find the correct address, we need to understand how Objective-C puts classes on the heap. When we have a pointer to an object, that memory points to the start of a blob of memory with information on that instance. The first word contains the isa pointer, and after that are the instance variables of the class (<a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html">see more in Apple’s documentation</a>). It looks like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WPtxLlJUZoWEzOGWnilXjw.png" /></figure><p>At some offset from the UITableView pointer is the memory representing _firstResponderIndexPath. Its <em>value</em> is the pointer to the IndexPath. When _firstResponderIndexPath changes, it will look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DG65bKefpFOPThTXZAW7AQ.png" /></figure><p>The memory at 0xc0000000000400016 won’t change since it’s an immutable object; there’s no point watching that. Instead, we want to watch the memory at a specific offset from our UITableView pointer. This will always be the same offset, but we need to find it. Let’s look at a memory dump around this pointer.</p><p>To view memory in Xcode, go to Debug → Debug Workflow → View Memory. Set the address to the pointer for the UITableView (in this case 0x7fefb482da00) and set the number of bytes to 4096. Now, we need to search for the value: 0xc0000000000400016. Using Cmd+F, we can see it highlighted in the middle of the dump:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_qZNaAF6RyM1LWSej3kFIQ.png" /></figure><p>Notice that memory is laid out backwards in this view, so the value reads 16 00 40 00 00 00 00 C0. Using the memory location values on the left, we can see that this value is at address140667502387512 (0x7fefb482e138).</p><p>Let’s try watching this address. (Note: this command doesn’t work if you’re in a Swift frame. To make it work, change your stack frame or use the pause button.)</p><pre><strong>(lldb) watchpoint set expression -- (void*)</strong><strong>0x7fefb482e138<br></strong>Watchpoint created: Watchpoint 1: addr = 0x7fefb482e138 size = 8 state = enabled type = w</pre><pre>new value: 0xc000000000400016</pre><p>In the app, let’s do something which we think will change this value. In this case, we set a different cell to be first responder. As soon as we do this, the breakpoint hits and we can see a backtrace. Often the breakpoint will hit twice: once when the value is set to nil, and again when the new value is set.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NfDooTb_WCQ7KI1C3_uNOA.png" /></figure><p>Finding the exact offset can be difficult, but we need only do it once. The instance variable is always at a constant offset. In this case, the table view was at 0x7fefb482da00 and the instance variable was at 0x7fefb482e138. The offset here is 1,848. We can now take any UITableView pointer and add 1,848 to get the pointer for the instance variable _firstResponderIndexPath.</p><pre><strong>(lldb) po tableView<br></strong>&lt;UITableView: 0x7ffd0d027800; frame = (0 0; 375 812); clipsToBounds = YES; gestureRecognizers = &lt;NSArray: 0x600000053e60&gt;; layer = &lt;CALayer: 0x60000002f800&gt;; contentOffset: {0, 93}; contentSize: {375, 1320}; adjustedContentInset: {88, 0, 34, 0}&gt;</pre><pre><strong>(lldb) po 0x7ffd0d027800 + 1848<br></strong>140724821720888</pre><pre><strong>(lldb) watch set expression -- (void *)140724821720888<br></strong>Watchpoint created: Watchpoint 1: addr = 0x7ffd0d027f38 size = 8 state = enabled type = w</pre><pre>new value: 0x0000000000000000</pre><h3>Conclusion</h3><p>Every ambitious project will encounter critical bugs in runtimes and frameworks. Sometimes, as with UIKit, those libraries will be private and closed source. Normally, this would be game over.</p><p>However, by reading private variables, swizzling property changes, and watching the right parts of memory, we can almost always find workarounds. We’ve successfully used these techniques to track down some otherwise showstopper bugs!</p><p>— <a href="https://twitter.com/plivesey453">Peter Livesey</a>, Lead Engineer, <a href="https://superhuman.com/?utm_source=medium&amp;utm_medium=blog&amp;utm_campaign=advanced-swift-debugging">Superhuman</a></p><p><em>At Superhuman we’re rebuilding the email experience for web &amp; mobile. Think vim / Sublime for email: blazingly fast and visually gorgeous.</em></p><p><em>Thank you to </em><a href="https://twitter.com/ahussein"><em>Akram</em></a><em>, </em><a href="https://twitter.com/_supermarin"><em>Marin</em></a><em>, </em><a href="https://twitter.com/colinta"><em>Colin</em></a><em>, and </em><a href="https://twitter.com/cezary_wojcik"><em>Cezary</em></a><em> for reviewing drafts of this post.</em></p><p><em>If you love solving interesting problems in elegant ways — join us! </em><a href="https://superhuman.com/jobs?utm_source=medium&amp;utm_medium=blog&amp;utm_campaign=advanced-swift-debugging"><em>Learn more</em></a><em> or </em><a href="mailto:hello@superhuman.com"><em>email us</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e154d1c28aaf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/superhuman-co/advanced-swift-debugging-for-uikit-e154d1c28aaf">Advanced Swift debugging for UIKit</a> was originally published in <a href="https://medium.com/superhuman-co">Superhuman</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>