<?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:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Tim Miko]]></title><description><![CDATA[A collection of thoughts, stories, and ideas about building software]]></description><link>https://tim.engineering/</link><image><url>https://tim.engineering/favicon.png</url><title>Tim Miko</title><link>https://tim.engineering/</link></image><generator>Ghost 5.79</generator><lastBuildDate>Fri, 23 Feb 2024 08:03:52 GMT</lastBuildDate><atom:link href="https://tim.engineering/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How to use Xcode debugging tools on a cold app start]]></title><description><![CDATA[Have you ever struggled with debugging functionality in your app during app launch? Here is how you can make Xcode automatically attach to your app.]]></description><link>https://tim.engineering/xcode-debugging-tools-app-start/</link><guid isPermaLink="false">5e39dfceb5030a00385c725f</guid><dc:creator><![CDATA[Tim Miko]]></dc:creator><pubDate>Mon, 17 Feb 2020 21:03:45 GMT</pubDate><content:encoded><![CDATA[<p>Have you ever struggled with debugging functionality in your app during app launch? Perhaps you are testing deep links or some other form of launching your app that doesn&apos;t involve Xcode launching it and wished you could set a breakpoint to look at what is going on under the hood. This is often time consuming to build and test without Xcode&apos;s debugging tools. </p><p>The struggle is over! Here is how you can make Xcode automatically attach to your iOS app for debugging purposes:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tim.engineering/content/images/2020/02/Screen-Shot-2020-02-04-at-4.28.01-PM.png" class="kg-image" alt loading="lazy"><figcaption>Select Attach to <em>Process by PID or Name...</em> from Xcode&apos;s Debug&#xA0;</figcaption></figure><p>Xcode includes this useful function in the Debug menu named <em>Attach to Process</em>. This presents a dialog that enables you to tell Xcode to wait for your app&apos;s process to to start running.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tim.engineering/content/images/2020/02/Screen-Shot-2020-02-04-at-4.32.00-PM-3.png" class="kg-image" alt loading="lazy"><figcaption>Start typing your app&apos;s process name and then click <em>Attach</em></figcaption></figure><p>Launch your app by clicking on its, triggering a deep link, etc. and Xcode will automatically attach to its process and enable the debugger. Now, you can set breakpoints, debug the view hierarchy, and more using Xcode&apos;s debugging tools &#x1F389;</p>]]></content:encoded></item><item><title><![CDATA[Kick your 3rd party networking library to the curb]]></title><description><![CDATA[I had the pleasure of speaking at 360iDev about networking at Strava. Check out my slides and leave a comment!]]></description><link>https://tim.engineering/360idev-talk-2019/</link><guid isPermaLink="false">5d644d4f23873700385baeae</guid><category><![CDATA[Conference Talks]]></category><dc:creator><![CDATA[Tim Miko]]></dc:creator><pubDate>Mon, 26 Aug 2019 21:47:06 GMT</pubDate><content:encoded><![CDATA[<figure class="kg-card kg-embed-card"><iframe width="480" height="270" src="https://www.youtube.com/embed/PqVcIHgDyCs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p>I had the pleasure of speaking at <a href="https://360idev.com/?ref=tim.engineering">360iDev</a> about networking at <a href="https://www.strava.com/?ref=tim.engineering">Strava</a>. I highly recommend this conference. It is an awesome community of folks with big ideas! </p><p>You can find my slides on Google Drive <a href="https://docs.google.com/presentation/d/11GdHCqS7NBPrgJ6inwOJn9MisjoHZwPjyIFKhwFY8BU/edit?usp=sharing&amp;ref=tim.engineering">here</a>. Feel free to leave a comment or send me an email if you have any questions.</p><p>You can find the code in this presentation on <a href="https://github.com/timothymiko/swift-networking-examples?ref=tim.engineering">Github</a>.</p>]]></content:encoded></item><item><title><![CDATA[Use the Ladder of Errors to improve your code quality]]></title><description><![CDATA[Software that crashes is a terrible experience. The Ladder of Errors is a suite we can use to surface software issues sooner in the development process.]]></description><link>https://tim.engineering/improve-code-quality-with-error-ladder/</link><guid isPermaLink="false">5c9e47284eab1500c057931f</guid><dc:creator><![CDATA[Tim Miko]]></dc:creator><pubDate>Thu, 25 Apr 2019 12:00:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1456406644174-8ddd4cd52a06?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1456406644174-8ddd4cd52a06?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Use the Ladder of Errors to improve your code quality"><p>Software that crashes on users is a terrible experience. People have a tolerance for &#xA0;software issues, but will eventually stop using it as they continually encounter friction. Some of the most frequent negative user reviews in the App Store, Google Play store, etc. are the result of software behaving unexpectedly or crashing altogether. </p><p>As an engineer, there are many tools we have at our disposal to mitigate software issues before they make it out into the wild. We can use things like compile-time errors or intentional runtime errors to give us a nudge when something isn&apos;t right. The focus of this article is to introduce the <em><strong>Ladder of Errors</strong> as </em>a suite we can use to surface software issues sooner in the development process and improve the quality of the software that is shipped to users. There are multiple levels in the ladder with each level moving closer to being a user-facing problem. </p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/04/ladder-of-errors.png" class="kg-image" alt="Use the Ladder of Errors to improve your code quality" loading="lazy"></figure><h3 id="compile-time-errors">Compile-Time Errors</h3><p>The first and most helpful of the errors are those that occur when you compile your code. It makes it easier to address issues given how immediate these kinds of errors are. This category is not limited to compiler errors, but it also includes other compile-time operations like <a href="https://en.wikipedia.org/wiki/Lint_(software)?ref=tim.engineering">linters</a> and build-scripts.</p><p>Let&apos;s take a look at an example in Swift of how we can design a system in a way that the compiler will throw an error if the system isn&apos;t changed properly. For the sake of this example, let&apos;s assume we are building a system for a dog hotel where there are different instructions for different breeds of dogs. We&apos;ll start by defining an enum with the two breeds we want to handle for now.</p><!--kg-card-begin: markdown--><pre><code class="language-swift">enum DogBreed {
    case poodle
    case borderCollie
}
</code></pre>
<!--kg-card-end: markdown--><p>We have two important functions at our dog hotel: <em>feeding</em> and <em>grooming</em> the dogs. Let&apos;s define those functions:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">func feed(_ dog: DogBreed) {
    switch dog {
    case .poodle, .borderCollie:
        print(&quot;feed kibble!&quot;)
    }
}

func groom(_ dog: DogBreed) {
    switch dog {
    case .poodle:
        print(&quot;give bath then dry!&quot;)
    case .borderCollie:
        print(&quot;give bath then dry then brush!&quot;)
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>Now, when we expand our hotel to support other dog breeds, we will get a compiler error if we don&apos;t provide feeding or grooming instructions.</p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/04/Screen-Shot-2019-04-16-at-8.23.54-AM.png" class="kg-image" alt="Use the Ladder of Errors to improve your code quality" loading="lazy"></figure><p>While compile-time errors are great because they provide near-immediate feedback, we simply can&apos;t catch everything at this stage. The next level of the ladder is dependent on your workflow using pull requests to merge code, but it is a valuable tool nonetheless.</p><h3 id="pull-request-errors">Pull-Request Errors</h3><p><a href="https://help.github.com/en/articles/about-pull-requests?ref=tim.engineering">Pull requests</a> are an opportunity for others to review your code and suggest improvements. It is also a great time to run longer operations that don&apos;t make sense to perform every time you build your project. This category is relatively broad and has a lot of space for creativity. Here are a few examples of things you can do during pull requests improve the quality of your code:</p><!--kg-card-begin: markdown--><ul>
<li>Automate common code review tasks with tools like <a href="https://danger.systems/?ref=tim.engineering">danger</a> (e.g. make sure all strings are added to translations file)</li>
<li>Run continus integration (CircleCI, Jenkins, etc.) to make sure your entire project builds</li>
<li>Run all unit tests for your project and ensure they pass before merging</li>
</ul>
<!--kg-card-end: markdown--><p>Once your code is out of your hands, it becomes more diffcult to detect and understand errors. Sometimes errors result in crashes and sometimes they simply cause your app to get into an unintended state. This is where runtime errors come into play.</p><h3 id="runtime-errors">Runtime Errors</h3><p>One of the most helpful ways to surface errors while using your app is to intentionally crash it. While this may sound a bit weird, it has saved me numerous times by explicitly making an issue known by crashing the app when it might have otherwise gone unknown and caused problems down the road.</p><p>Let&apos;s look at an example. Let&apos;s say we wanted to provide an image to display alongside each dog breed:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">enum DogBreed {
    case poodle
    case borderCollie

    var imageURL: URL {
        switch self {
        case .poodle:
            guard let url = URL(string: &quot;not a valid url .com&quot;) else {
                fatalError(&quot;Invalid image url for poodle!&quot;)
            }
            return url
        case .borderCollie:
            guard let url = URL(string: &quot;htp://borderCollie.com/image.jpg&quot;) else {
                fatalError(&quot;Invalid image url for borderCollie!&quot;)
            }
            return url
        }
    }
}

// do something with image of dog
print(DogBreed.poodle.imageURL.absoluteString)
</code></pre>
<!--kg-card-end: markdown--><p>The <code>URL(string: ...)</code> constructor returns an optional <code>URL?</code>. In this example, the &quot;not a valid url .com&quot; string causes the <code>URL</code> constructor to return <code>nil</code>. Realistically, the use case here is safeguarding against typos such as entering <code>htps</code> instead of <code>https</code> or something similar. </p><p>The other nice benfit of using <code>fatalError()</code> is that we can work with <code>URL</code> type instead of an optional. In the latter case, many resort to force unwrapping which has its use cases and could achieve the same outcome, but unwrapping and providing a contextual message when calling <code>fatalError</code> can help debug things easier.</p><h3 id="error-logs-in-production">Error Logs in Production</h3><p>The last level in the error ladder is using error logs in production to understand when things aren&apos;t working as they should. Crash logs are very helpful, but sometimes can be vague and are not always straightforward when it comes to pinpointing the root cause. Furthermore, it can be helpful to understand when things aren&apos;t working as expected even when your application does not crash.</p><p>Many error reporting tools provide the ability to leave contextual messages around events that occur in the moments leading up to an error. There are many different names (Crashlytics calls it <em><a href="https://docs.fabric.io/apple/crashlytics/enhanced-reports.html?ref=tim.engineering#custom-logging-in-swift">Custom Logging</a>, </em>Bugsnag calls them <em><a href="https://docs.bugsnag.com/platforms/ios/customizing-error-reports/?ref=tim.engineering">Breadcrumbs</a>) </em>they all can be used to achieve the same thing at the end of the day: provide more information about what caused your app to crash.</p><p>I also mentioned logging errors that don&apos;t cause your app to crash. It is not a good experience for users to have an app crash while using it, so it is good practice to handle errors where possible. Most error reporting tools provide the ability to report handled errors (<a href="crashlytics swift nonfatal errors">Crashlytics</a>, <a href="https://docs.bugsnag.com/platforms/ios/?ref=tim.engineering#reporting-handled-exceptions">Bugsnag</a>) which can be extremely helpful to understand how often some of particular errors are occurring.</p><h3 id="conclusion">Conclusion</h3><p>At the end of the day, there are many tools at our disposal and it is up to each of us how we utilize them to improve the quality of our work. I laid of this <em>Ladder of Errors</em> merely as a platform-agnostic tool to help engineers understand how to use various design paradigms and error reporting tools to improve the stability of their code and surface errors earlier on in the development process.</p>]]></content:encoded></item><item><title><![CDATA[It's time to break up with your networking library for URLSession]]></title><description><![CDATA[<p>Dear <em>{INSERT NETWORKING LIBRARY NAME HERE}</em>,</p><p>There is no simple way to say this, but our time together is over. You have caused me too many headaches. From <a href="https://github.com/AFNetworking/AFNetworking/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+memory+leak&amp;ref=tim.engineering">countless memory leaks</a> to upgrade issues, I simply can&apos;t do it anymore.</p><p>There was a time when your troubles were</p>]]></description><link>https://tim.engineering/break-up-third-party-networking-urlsession/</link><guid isPermaLink="false">5c91c4d5d66e3300cc37541c</guid><dc:creator><![CDATA[Tim Miko]]></dc:creator><pubDate>Thu, 28 Mar 2019 08:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Dear <em>{INSERT NETWORKING LIBRARY NAME HERE}</em>,</p><p>There is no simple way to say this, but our time together is over. You have caused me too many headaches. From <a href="https://github.com/AFNetworking/AFNetworking/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+memory+leak&amp;ref=tim.engineering">countless memory leaks</a> to upgrade issues, I simply can&apos;t do it anymore.</p><p>There was a time when your troubles were worth it. Back in the day when you handled all of the communication with <a href="https://developer.apple.com/documentation/foundation/nsurlconnection?ref=tim.engineering">NSURLConnection</a>, things were great. It was easy to justify the effort involved in your upkeep. You had to coordinate with NSURLConnection&apos;s many delegate methods to simply receive a response and response body. Working with NSURLConnection was not fun. I was happy to give those responsibilities to you.</p><p>You filled a clear void. You and many of your cousins were among the top charts of popular iOS 3rd party frameworks. All of you came with a laundry-list of functionality out of the box. However, none of you are free.</p><p>Integrating you into my app has negative side-effects like increasing either my app&apos;s startup time or size. Furthermore, delegating my entire networking layer to you has opened me up to all of your vulnerabilities and prevented me from customizing components of my networking layer.</p><p>Over time, Apple has improved the APIs for making HTTP and HTTPS requests. We no longer have to deal with NSURLConnection. I now have <a href="https://developer.apple.com/documentation/foundation/nsurlsession?ref=tim.engineering">NSURLSession</a> at my disposal, which is <em>much</em> easier to use. On top of that, I don&apos;t even have to worry about encoding or decoding Data anymore with the introduction of <a href="https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types?ref=tim.engineering">Codable in Swift</a>. </p><p>At this point, you are dragging me down and holding me back more than anything. I took a little test drive with building my own networking layer and decided that it is time to make the switch and remove you from my project.</p><p>I hope you understand. I included some examples from my networking layer below to help you understand where I am coming from. </p><p>All the best,</p><p>Tim</p><hr><p>Here is a basic Swift API client:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">enum APIError: Error {
    case invalidURL
    case requestFailed
}

struct APIClient {

    typealias APIClientCompletion = (HTTPURLResponse?, Data?, APIError?) -&gt; Void

    private let session = URLSession.shared
    private let baseURL = URL(string: &quot;https://jsonplaceholder.typicode.com&quot;)

    func request(method: String, path: String, _ completion: @escaping APIClientCompletion) {
        guard let url = baseURL?.appendingPathComponent(path) else {
            completion(nil, nil, .invalidURL); return
        }

        var request = URLRequest(url: url)
        request.httpMethod = method

        let task = session.dataTask(with: url) { (data, response, error) in
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(nil, nil, .requestFailed); return
            }
            completion(httpResponse, data, nil)
        }
        task.resume()
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>In less than 30 lines of code, we were able to get a decent API client off the ground and working, error handling included. Here is an example of this client in action:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">APIClient().request(method: &quot;get&quot;, path: &quot;todos/1&quot;) { (_, data, _) in
    if let data = data, let result = String(data: data, encoding: .utf8) {
        print(result)
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>For simple use cases, the example above may be all that is needed. However, many applications include an abundance of network requests of varying complexities. </p><p>For example, using the example above, you wouldn&apos;t be able to make a request with query parameters (e.g. <code>/todos/?hello=world</code>) or with a request body. Furthermore, given that Swift thrives on its strongly-typed nature, using a <code>String</code> type for the <code>method</code> parameter is error-prone and repetitive. </p><p>Let&apos;s take a look at Swift API client that has better support for making requests:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">enum HTTPMethod: String {
    case get = &quot;GET&quot;
    case put = &quot;PUT&quot;
    case post = &quot;POST&quot;
    case delete = &quot;DELETE&quot;
    case head = &quot;HEAD&quot;
    case options = &quot;OPTIONS&quot;
    case trace = &quot;TRACE&quot;
    case connect = &quot;CONNECT&quot;
}

struct HTTPHeader {
    let field: String
    let value: String
}

class APIRequest {
    let method: HTTPMethod
    let path: String
    var queryItems: [URLQueryItem]?
    var headers: [HTTPHeader]?
    var body: Data?

    init(method: HTTPMethod, path: String) {
        self.method = method
        self.path = path
    }
}

enum APIError: Error {
    case invalidURL
    case requestFailed
}

struct APIClient {

    typealias APIClientCompletion = (HTTPURLResponse?, Data?, APIError?) -&gt; Void

    private let session = URLSession.shared
    private let baseURL = URL(string: &quot;https://jsonplaceholder.typicode.com&quot;)!

    func request(_ request: APIRequest, _ completion: @escaping APIClientCompletion) {

        var urlComponents = URLComponents()
        urlComponents.scheme = baseURL.scheme
        urlComponents.host = baseURL.host
        urlComponents.path = baseURL.path
        urlComponents.queryItems = request.queryItems

        guard let url = urlComponents.url?.appendingPathComponent(request.path) else {
            completion(nil, nil, .invalidURL); return
        }

        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = request.method.rawValue
        urlRequest.httpBody = request.body

        request.headers?.forEach { urlRequest.addValue($0.value, forHTTPHeaderField: $0.field) }

        let task = session.dataTask(with: url) { (data, response, error) in
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(nil, nil, .requestFailed); return
            }
            completion(httpResponse, data, nil)
        }
        task.resume()
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>There are a few changes here. The biggest change is that the <code>APIClient</code> now accepts an <code>APIRequest</code> object. All of the data provided in <code>APIRequest</code> is then transformed into a <code>URLRequest</code>. Here is an example request:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">let request = APIRequest(method: .post, path: &quot;posts&quot;)
request.queryItems = [URLQueryItem(name: &quot;hello&quot;, value: &quot;world&quot;)]
request.headers = [HTTPHeader(field: &quot;Content-Type&quot;, value: &quot;application/json&quot;)]
request.body = Data() // example post body

APIClient().request(request) { (_, data, _) in
    if let data = data, let result = String(data: data, encoding: .utf8) {
        print(result)
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>We are now setup to making more powerful API requests. However, there is still some room for bigger improvements. Swift 4 introduced <code><a href="https://developer.apple.com/documentation/foundation/jsonencoder?ref=tim.engineering">JSONEncoder</a></code> and <code><a href="https://developer.apple.com/documentation/foundation/jsondecoder?ref=tim.engineering">JSONDecoder</a></code> which make it extremely easy to encode and decode JSON data from and to Swift object types. </p><p>Additionally, consumers of <code>APIClient</code>&apos;s response shouldn&apos;t need to interact directly with the underlying types that <code>APIClient</code> is currently returning (i.e. <code>HTTPURLResponse</code> and <code>Data</code>).</p><p>Let&apos;s take a look at an example that improves upon <code>APIClient</code> even further:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">enum HTTPMethod: String {
    case get = &quot;GET&quot;
    case put = &quot;PUT&quot;
    case post = &quot;POST&quot;
    case delete = &quot;DELETE&quot;
    case head = &quot;HEAD&quot;
    case options = &quot;OPTIONS&quot;
    case trace = &quot;TRACE&quot;
    case connect = &quot;CONNECT&quot;
}

struct HTTPHeader {
    let field: String
    let value: String
}

class APIRequest {
    let method: HTTPMethod
    let path: String
    var queryItems: [URLQueryItem]?
    var headers: [HTTPHeader]?
    var body: Data?

    init(method: HTTPMethod, path: String) {
        self.method = method
        self.path = path
    }

    init&lt;Body: Encodable&gt;(method: HTTPMethod, path: String, body: Body) throws {
        self.method = method
        self.path = path
        self.body = try JSONEncoder().encode(body)
    }
}

struct APIResponse&lt;Body&gt; {
    let statusCode: Int
    let body: Body
}

extension APIResponse where Body == Data? {
    func decode&lt;BodyType: Decodable&gt;(to type: BodyType.Type) throws -&gt; APIResponse&lt;BodyType&gt; {
        guard let data = body else {
            throw APIError.decodingFailure
        }
        let decodedJSON = try JSONDecoder().decode(BodyType.self, from: data)
        return APIResponse&lt;BodyType&gt;(statusCode: self.statusCode,
                                     body: decodedJSON)
    }
}

enum APIError: Error {
    case invalidURL
    case requestFailed
    case decodingFailure
}

enum APIResult&lt;Body&gt; {
    case success(APIResponse&lt;Body&gt;)
    case failure(APIError)
}

struct APIClient {

    typealias APIClientCompletion = (APIResult&lt;Data?&gt;) -&gt; Void

    private let session = URLSession.shared
    private let baseURL = URL(string: &quot;https://jsonplaceholder.typicode.com&quot;)!

    func perform(_ request: APIRequest, _ completion: @escaping APIClientCompletion) {

        var urlComponents = URLComponents()
        urlComponents.scheme = baseURL.scheme
        urlComponents.host = baseURL.host
        urlComponents.path = baseURL.path
        urlComponents.queryItems = request.queryItems

        guard let url = urlComponents.url?.appendingPathComponent(request.path) else {
            completion(.failure(.invalidURL)); return
        }

        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = request.method.rawValue
        urlRequest.httpBody = request.body

        request.headers?.forEach { urlRequest.addValue($0.value, forHTTPHeaderField: $0.field) }

        let task = session.dataTask(with: url) { (data, response, error) in
            guard let httpResponse = response as? HTTPURLResponse else {
                completion(.failure(.requestFailed)); return
            }
            completion(.success(APIResponse&lt;Data?&gt;(statusCode: httpResponse.statusCode, body: data)))
        }
        task.resume()
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>It is now extremely easy to include JSON data in requests in addition to decoding JSON data into strongly-typed Swift objects. Additionally, there is a clear contract now between the <code>APIClient</code> and its consumers as to when a request is successful as well as providing informative errors.</p><p>Let&apos;s take a look at an example of using the latest iteration of <code>APIClient</code>:</p><!--kg-card-begin: markdown--><pre><code class="language-swift">struct Post: Decodable {
    let userId: Int
    let id: Int
    let title: String
    let body: String
}

let request = APIRequest(method: .get, path: &quot;posts&quot;)

APIClient().perform(request) { (result) in
    switch result {
    case .success(let response):
        if let response = try? response.decode(to: [Post].self) {
            let posts = response.body
            print(&quot;Received posts: \(posts.first?.title ?? &quot;&quot;)&quot;)
        } else {
            print(&quot;Failed to decode response&quot;)
        }
    case .failure:
        print(&quot;Error perform network request&quot;)
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>This example demonstrates how easy it is to perform an API request and make use of its result. This last example may seem similar to common interfaces of 3rd party libraries. There isn&apos;t anything inherently wrong with this. The under-the-hood benefits are truly the biggest win here.</p><p><code>APIClient</code> has grown over the course of these examples, but all send and done, it is still less than 100 hundred lines. Furthermore, this fully-featured system is not reliant on any 3rd party code. I&apos;ll dive into this topic more in the future, but this is extremely valuable because it gives you more control over your code. As an app changes and requirements change, which is guaranteed to happen, having a flexible <code>APIClient</code> will pay off.</p><hr><p>If you&apos;re interested in diving deeper into the examples above, I published an Xcode playground on Github <a href="https://github.com/timothymiko/swift-networking-examples?ref=tim.engineering">here</a>.</p>]]></content:encoded></item><item><title><![CDATA[How to find memory leaks in an iOS app]]></title><description><![CDATA[<p>Memory is leaked in an iOS app when the system is unable to determine if an object allocated in memory is in use or not. The most frequent cause of memory leaks in iOS apps are <em>retain cycles</em>. Check out my previous post for <a href="https://tim.engineering/detailed-explanation-memory-leaks-ios-apps/"><em>a more detailed explanation of memory</em></a></p>]]></description><link>https://tim.engineering/how-to-find-memory-leaks-in-ios-app/</link><guid isPermaLink="false">5c858dd27ed2b300c01b8126</guid><dc:creator><![CDATA[Tim Miko]]></dc:creator><pubDate>Thu, 14 Mar 2019 06:00:00 GMT</pubDate><media:content url="https://tim.engineering/content/images/2019/03/luemen-carlson-1072864-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://tim.engineering/content/images/2019/03/luemen-carlson-1072864-unsplash.jpg" alt="How to find memory leaks in an iOS app"><p>Memory is leaked in an iOS app when the system is unable to determine if an object allocated in memory is in use or not. The most frequent cause of memory leaks in iOS apps are <em>retain cycles</em>. Check out my previous post for <a href="https://tim.engineering/detailed-explanation-memory-leaks-ios-apps/"><em>a more detailed explanation of memory leaks in iOS apps</em></a>. This post focuses on using Xcode tools to find and identify the causes of memory leaks in iOS apps.</p><p>To get started, you&apos;ll need to enable a couple settings in Xcode. Before enabling these settings, it is important note that you will want to make sure you disable the settings after you are done with your memory leak hunt. Both settings will have negative performance impacts if left enabled all the time.</p><p>First, edit the scheme for your app in Xcode.</p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/03/Screen-Shot-2019-03-10-at-8.34.58-PM.png" class="kg-image" alt="How to find memory leaks in an iOS app" loading="lazy"></figure><p>Click on the <em>Run</em> scheme and then select the <em>Diagnostics</em> section. There are two settings in this section that need to be enabled. The first is <em>Malloc Scribble</em> in the Memory Management group.</p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/03/Screen-Shot-2019-03-10-at-8.17.42-PM.png" class="kg-image" alt="How to find memory leaks in an iOS app" loading="lazy"></figure><p>Enabling <a href="https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html?ref=tim.engineering"><em>MallocScribble</em></a> will fill freed memory with a predefined value that makes it more obvious when memory is leaked. This increases Xcode&apos;s accuracy of identifying leaks.</p><p>The second setting to enable is <em>Malloc Stack</em> in the Logging group.</p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/03/Screen-Shot-2019-03-10-at-8.18.00-PM.png" class="kg-image" alt="How to find memory leaks in an iOS app" loading="lazy"></figure><p>Enabling <a href="https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html?ref=tim.engineering"><em>MallocStackLogging</em></a> will allow Xcode to build an allocation backtrace to help you understand where objects are being referenced from. </p><p>That is all that is needed as far as configuring Xcode goes. Let&apos;s take a look at an example task manager app. If you are interesting in following along interactively, the source code is freely available on <a href="https://github.com/timothymiko/ios-memory-leaks?ref=tim.engineering">Github</a>. Now let&apos;s get hunting for memory leaks. The example app consists of three main objects.</p><p>The first is <em>TaskListViewController </em>which is responsible for viewing tasks:</p><!--kg-card-begin: markdown--><pre><code>class TaskListViewController: UIViewController {
    
    @IBAction func showCreateTaskViewController() {
        let createTaskViewController = CreateTaskViewController()
        present(createTaskViewController, animated: true, completion: nil)
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>The second is <em>CreateTaskWorker</em> which is responsible for creating a new task (i.e. saving it to a database):</p><!--kg-card-begin: markdown--><pre><code>protocol CreateTaskWorkerDelegate {
    func didCreateTask()
}

class CreateTaskWorker {
    
    var delegate: CreateTaskWorkerDelegate?
    
    func createTask(named name: String) {
        delegate?.didCreateTask()
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>The last is <em>CreateTaskViewController</em> which is responsible for accepting user input for a new task and communicating it to the worker:</p><!--kg-card-begin: markdown--><pre><code>class CreateTaskViewController: UIViewController, CreateTaskWorkerDelegate {
    
    private let createTaskWorker = CreateTaskWorker()

    init() {
        super.init(nibName: &quot;CreateTaskViewController&quot;, bundle: nil)
        createTaskWorker.delegate = self
    }
    
    @IBAction func createTask() {
        createTaskWorker.createTask(named: &quot;Pay bills&quot;)
    }
    
    @IBAction func dismiss() {
        dismiss(animated: true, completion: nil)
    }
    
    func didCreateTask() {
        print(&quot;Task created&quot;)
    }
}
</code></pre>
<!--kg-card-end: markdown--><p><em>TaskListViewController</em> presents <em>CreateTaskViewController</em>. Tap through the flow a couples times: </p><ul><li>Tap <em>New Task</em> button (<em>CreateTaskViewController</em> is presented)</li><li>Tap <em>Dismiss</em> button (<em>CreateTaskViewController</em> is dismissed)</li></ul><p>Now, click on the <em>Debug Memory Graph</em> button in Xcode&apos;s <em>Variables View </em>at the bottom left<em>.</em></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tim.engineering/content/images/2019/03/debug-memory-graph.jpg" class="kg-image" alt="How to find memory leaks in an iOS app" loading="lazy"><figcaption>Debug Memory Graph button in Xcode&apos;s Variables View</figcaption></figure><p>This will load the application&apos;s memory graph. Now, select the <em>Debug</em> tab in Xcode&apos;s <em>Navigator</em> pane on the left. This will bring up a list of all objects in memory.</p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/03/debug-navigator.jpg" class="kg-image" alt="How to find memory leaks in an iOS app" loading="lazy"></figure><p>At this point, given that we have dismissed all instances of <em>CreateTaskViewController</em>, we should only expect to see a single instance of <em>TaskListViewController </em>here. </p><p>Notice that there are instances of <em>CreateTaskViewController</em> with a purple exclamation point icon next to it. This is Xcode indicating that an object has been leaked. </p><p>This post is focused more on identifying memory leaks and less on why they are occurring. To gain a better understanding of why this memory leak is occuring, read my previous article: <a href="https://tim.engineering/detailed-explanation-memory-leaks-ios-apps/"><em>A detailed explanation of memory leaks in iOS apps</em></a><em>.</em></p><p>If you click on one of the instances in debug navigator, it will present you with a relationship graph. This view is extremely helpful for understanding which references are still being held as well as for tracking down where references are created.</p><figure class="kg-card kg-image-card"><img src="https://tim.engineering/content/images/2019/03/debugger.jpg" class="kg-image" alt="How to find memory leaks in an iOS app" loading="lazy"></figure><p>Now that we found our memory leak, we can go about fixing it. For this particular example, all it takes is denoting the delegate in <em>CreateTaskWorker</em> as <strong>weak</strong>:</p><!--kg-card-begin: markdown--><pre><code>protocol CreateTaskWorkerDelegate: class {
    func didCreateTask()
}

class CreateTaskWorker {
    
    weak var delegate: CreateTaskWorkerDelegate?
    
    func createTask(named name: String) {
        delegate?.didCreateTask()
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>If you make these changes and re-run the <em>Tasks</em> app, you&apos;ll notice that the memory leak no longer occurs. </p><p>Congrats! You are now ready to go out and find memory leaks in iOS apps. These debugging tools are incredibly powerful and can provide deep insight into the inner workings of of your application. </p><p>Xcode is not always 100% accurate with identifying memory leaks as seen in the screenshot above where only 3 out of the 4 leaked instances each of <em>CreateTaskWorker and CreateTaskViewController</em> were marked by Xcode as leaked. </p><p>Furthermore, some retain cycles, one of the most common causes of memory leaks in iOS apps, don&apos;t last forever, but still last long enough to cause issues. The method outlined in this article will work for identifying these cases, but only if you trigger the memory graph while the retain cycle is occuring. Otherwise, the objects will be deallocated if you wait too long. Look out for a future article with further strategies for debugging these cases as they are more common that you might think!</p><p>Lastly, don&apos;t forget to turn off the <em>MallocScribble</em> and <em>MallocStackLogging</em> settings in the run scheme for your app and you are done hunting for memory leaks. This will have a negative performance impact otherwise.</p>]]></content:encoded></item><item><title><![CDATA[A detailed explanation of memory leaks in iOS apps]]></title><description><![CDATA[Memory leaks in iOS can be extremely frustrating. Not only can they cause unintended and non-obvious consequences, vague crashes for example, but they can also be difficult to track down.]]></description><link>https://tim.engineering/detailed-explanation-memory-leaks-ios-apps/</link><guid isPermaLink="false">5c80284a7ed2b300c01b805a</guid><dc:creator><![CDATA[Tim Miko]]></dc:creator><pubDate>Fri, 08 Mar 2019 07:25:00 GMT</pubDate><content:encoded><![CDATA[<p>Memory leaks in iOS can be extremely frustrating. Not only can they cause unintended and non-obvious consequences, vague crashes for example, but they can also be difficult to track down. While memory leaks alone won&apos;t necessarily cause an application to crash, keeping instances of objects around longer than they should can lead to unintended behaviors. The crash log below is indirectly the result of a memory leak caused by a retain cycle in an iOS app.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tim.engineering/content/images/2019/03/Screen-Shot-2019-03-06-at-12.16.52-PM.jpeg" class="kg-image" alt loading="lazy"><figcaption>Example crash log indirectly caused by a memory leak</figcaption></figure><p>A memory leak occurs when the system is unable to determine if allocated space in memory is in use or not. Both Swift and Objective-C use <em>Automatic Reference Counting (ARC) </em>to manage space in memory. </p><p>ARC is a memory-management system that keeps track of how many references there are to a given object. When there are no longer any references to an object, the system knows that object is no longer needed and can be deallocated from memory. For a deeper dive into how <em>Automatic Reference Counting (ARC)</em> works, head over to the docs on <a href="https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html?ref=tim.engineering">Swift.org</a>.</p><p>The most frequent culprit of memory leaks in iOS is a retain cycle. A retain cycle prevents an object from being deallocated even after its creator has been deallocated. Here a brief example:</p><!--kg-card-begin: markdown--><pre><code>class Dog {
    var name: String
    var owner: Person?
  
    init(name: String) {
        self.name = name
    }
}

class Person {
    var name: String
    var dog: Dog?
  
    init(name: String) {
        self.name = name
    }
}

let myles = Dog(name: &quot;Myles&quot;)
let tim = Person(name: &quot;Tim&quot;)

myles.owner = tim
tim.dog = myles
</code></pre>
<!--kg-card-end: markdown--><p>In this example, both objects contain references to each other. Thus, even after their creator has been deallocated, both objects will remain in memory because their reference counts are both still greater than zero.</p><p>The solution to this problem is a <em>weak</em> reference that does not increment an object&apos;s counter and therefore does not affect an whether or not an object can be deallocated. Here is an updated version of the example above that does not cause a retain cycle:</p><!--kg-card-begin: markdown--><pre><code>class Dog {
    var name: String
    weak var owner: Person?
  
    init(name: String) {
        self.name = name
    }
}

class Person {
    var name: String
    weak var dog: Dog?
  
    init(name: String) {
        self.name = name
    }
}

let myles = Dog(name: &quot;Myles&quot;)
let tim = Person(name: &quot;Tim&quot;)

myles.owner = tim
tim.dog = myles
</code></pre>
<!--kg-card-end: markdown--><p>While retain cycles can occur between any objects, I have found the most frequent occurrence in iOS to be leaked instances of UIViewController given the long list of responsibilities delegated to it in a typical iOS app. </p><p>Asynchronous tasks such as network requests, database calls, image processing, etc. are easy candidates for unintentional retain cycles given that their interfaces typically involve a closure. Here is an example of a view controller that has a cycle:</p><!--kg-card-begin: markdown--><pre><code>class Worker {
    func performLongRunningTask(_ completion: () -&gt; Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            completion()
        }
    }
}

class ViewControllerA: UIViewController {

    private let worker = Worker()
    private var isTaskFinished = false

    override func viewDidLoad() {
        super.viewDiDLoad()
        worker.performLongRunningTask {
            self.markTaskFinished()
        }
    }
    
    func markTaskFinished() {
        isTaskFinished = true
    }
}
</code></pre>
<!--kg-card-end: markdown--><p><strong>ViewControllerA </strong>has a reference to a <strong>Worker</strong> object that performs a task that takes some time to complete. As a result, the worker object uses a closure to notify the call of its completion. In this example, <em>ViewControllerA</em> implicitly creates a strong reference from <em>Worker</em> to <em>ViewControllerA</em> by referencing <strong>self</strong> inside the closure passed to <em>Worker</em> as a parameter in the function <em>performLongRunningTask.</em></p><p>The solution to this problem is to use a <strong>weak</strong> reference to <strong>self</strong> like so:</p><!--kg-card-begin: markdown--><pre><code>class Worker {
    func performLongRunningTask(_ completion: () -&gt; Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            completion()
        }
    }
}

class ViewControllerB: UIViewController {
  
    private let worker = Worker()
    private var isTaskFinished = false

    override func viewDidLoad() {
        super.viewDiDLoad()
        worker.performLongRunningTask { [weak self] in
            self?.markTaskFinished()
        }
    }
    
    func markTaskFinished() {
        isTaskFinished = true
    }
}
</code></pre>
<!--kg-card-end: markdown--><p>In this example, <strong>ViewControllerB</strong> is still referencing <strong>self</strong> inside the closure passed to <em>Worker</em>, but it declared the reference weak by add <strong>[weak self]</strong> to the closure&apos;s parameters. This approach successfully avoids introducing a retain cycle if <em>ViewControllerB</em> is dismissed before <em>Worker</em> has finished its task. </p><p>When designing interfaces that require references to communicate, such as <em>Worker</em> in this example, it is important to use empathy and think about how other engineers will use your code. </p><p>Interacting with closures is easy, but it creates an easy opportunity to introduce retain cycles<em>. </em>The responsibility of avoiding a retain cycle now falls on the engineer interacting with <em>Worker, </em>who may not be the engineer who wrote the code for <em>Worker</em> and may not have a solid understanding of retain cycles.</p><p>Empathy is key here and we can use a common design pattern to remove this responsibility from the engineer interacting with <em>Worker</em>. Let&apos;s take a look at this example:</p><!--kg-card-begin: markdown--><pre><code>protocol WorkerDelegate {
    func taskDidComplete()
}

class Worker {
    weak var delegate: WorkerDelegate?

    func performLongRunningTask() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            self.delegate?.taskDidComplete()
        }
    }
}

class ViewControllerC: UIViewController {
  
    private let worker = Worker()
    private var isTaskFinished = false

    override func viewDidLoad() {
        super.viewDiDLoad()
        worker.delegate = self
        worker.performLongRunningTask()
    }
    
    func markTaskFinished() {
        isTaskFinished = true
    }
}

extension ViewControllerC: WorkerDelegate {
    func taskDidComplete() {
        markTaskFinished()
    }
}
</code></pre>
<!--kg-card-end: markdown--><p><em>ViewControllerC</em> has the same exact output as <em>ViewControllerB. </em>However, the interface for <em>Worker</em> is updated in this example to explicitly avoid introducing a retain cycle because the worker&apos;s delegate will always be a weak reference. </p><p>This common delegate pattern is just one example of how thoughtful design patterns can be used to write stronger, more reliable code. I encourage all engineers to use more empathy when writing code. </p><p>Thanks for reading and stay tuned for more!</p>]]></content:encoded></item></channel></rss>