<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://kenthumphries.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://kenthumphries.github.io/" rel="alternate" type="text/html" /><updated>2020-02-04T03:49:53+00:00</updated><id>https://kenthumphries.github.io/feed.xml</id><title type="html">kentios</title><subtitle>thinks about tech</subtitle><entry><title type="html">The *Right* Unit Tests</title><link href="https://kenthumphries.github.io/The-Right-Unit-Tests/" rel="alternate" type="text/html" title="The *Right* Unit Tests" /><published>2020-01-16T00:00:00+00:00</published><updated>2020-01-16T00:00:00+00:00</updated><id>https://kenthumphries.github.io/The-Right-Unit-Tests</id><content type="html" xml:base="https://kenthumphries.github.io/The-Right-Unit-Tests/">&lt;p&gt;This isn’t a post to teach the basics of unit testing on iOS. It’s designed for people who already write unit tests, but aren’t sure if they’re doing it &lt;em&gt;right&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/2020-01-16-The-Right-Unit-Test/alice-dietrich-messy-unsplash.jpg&quot; alt=&quot;Unit testing can get messy!&quot; /&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;b&gt;Unit testing can get messy&lt;/b&gt;&lt;br /&gt;&lt;i&gt;(photo by &lt;a href=&quot;https://unsplash.com/@alicegrace?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Alice Dietrich&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Just like code, tests should be clear, concise and simple for everyone to understand. It should require no effort to understand a test, even for someone who is not the author, and does not have the full context.&lt;/p&gt;

&lt;p&gt;This post is all about getting back to fundamentals and understanding what’s most valuable for unit tests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;#summary&quot;&gt;Jump to the Summary&lt;/a&gt;, or read this article &lt;a href=&quot;https://medium.com/@kentios/the-right-unit-tests-for-ios-7f9422ff7081?source=friends_link&amp;amp;sk=2242e561e92989c1c032477e99563a97&quot;&gt;on Medium&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;tools&quot;&gt;Tools&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/2020-01-16-The-Right-Unit-Test/cesar-carlevarino-aragon-tools-unsplash.jpg&quot; alt=&quot;All The Tools!&quot; /&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;b&gt;All The Tools!&lt;/b&gt;&lt;br /&gt;&lt;i&gt;(photo by &lt;a href=&quot;https://unsplash.com/@carlevarino?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Cesar Carlevarino Aragon&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;There are some great tools for unit testing iOS in Swift (for example &lt;a href=&quot;https://github.com/Quick/Quick&quot;&gt;Quick&lt;/a&gt;/&lt;a href=&quot;https://github.com/Quick/Nimble&quot;&gt;Nimble&lt;/a&gt;, &lt;a href=&quot;https://github.com/MakeAWishFoundation/SwiftyMocky&quot;&gt;SwiftyMocky&lt;/a&gt;, &lt;a href=&quot;https://github.com/pointfreeco/swift-snapshot-testing&quot;&gt;Snapshot-testing&lt;/a&gt;). I encourage you to use them! However, even with great tools, developers can still write bad tests. As an example, Quick (or any &lt;a href=&quot;https://en.wikipedia.org/wiki/Behavior-driven_development&quot;&gt;BDD&lt;/a&gt; framework) improves test naming &amp;amp; readability, but it’s important to first understand &lt;em&gt;why&lt;/em&gt; better naming is important. To explain these fundamental ideas, let’s just talk about plain vanilla XCTests.&lt;/p&gt;

&lt;h1 id=&quot;first-things-first&quot;&gt;FIRST Things First&lt;/h1&gt;

&lt;p&gt;If you’re not familiar with it, please take a minute to read about the &lt;a href=&quot;https://hackernoon.com/test-f-i-r-s-t-65e42f3adc17&quot;&gt;FIRST principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a short summary for context:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Fast:&lt;/strong&gt; Speedy tests are run more often&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Isolated:&lt;/strong&gt; One test must never be able to break another test&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Repeatable:&lt;/strong&gt; A test must always return exactly the same  result&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Self-Validating:&lt;/strong&gt; A clear name and single assertion identifies point of failure&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Thorough:&lt;/strong&gt; About confidence, not percentages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FIRST is a terrific set of values for tests. However, it’s a general testing principle, not a specific set of tips.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Here are practical tips to improve the quality of your tests, taking FIRST into account. The most important tips are presented first.&lt;/p&gt;

&lt;h1 id=&quot;1-kiss-and-short-stupid&quot;&gt;1. K.I.S.S. And Short, Stupid&lt;/h1&gt;

&lt;p&gt;Keep your tests short.&lt;/p&gt;

&lt;p&gt;Really short.&lt;/p&gt;

&lt;p&gt;A long test is a good indicator of smelly code. That is, testability and code complexity are intertwined. If your code is complicated, it’s likely that it will become a source of bugs. The same goes for tests - a complex test is less likely to catch a bug. Thinking “hmm, this code is difficult to test” should be reason enough to refactor your code. If you, the author, find it difficult to test your own code now, think about someone wanting to refactor this code in 6 months time.&lt;/p&gt;

&lt;p&gt;When tests are complex or long, it is almost certain that code can be further improved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try to keep your tests to 10 logical statements or fewer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(choose any number that increases your test quality over time)&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;2-test-quality--code-quality&quot;&gt;2. Test Quality ≠ Code Quality&lt;/h1&gt;

&lt;p&gt;It’s important to remember that good tests have different characteristics to code. A former colleague spent countless PR reviews teaching me that &lt;strong&gt;shared&lt;/strong&gt; test utilities (mocks, convenience factories, comparators) are dangerous. As developers, we learn the &lt;a href=&quot;https://wikipedia.org/wiki/Don't_Repeat_Yourself&quot;&gt;DRY&lt;/a&gt; principle at birth. But, as FIRST shows, isolation is actually a more important quality for tests.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/2020-01-16-The-Right-Unit-Test/erik-witsoe-dry-washing-unsplash.jpg&quot; alt=&quot;We don't always need things to be DRY&quot; /&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;b&gt;We don't always need things to be DRY&lt;/b&gt;&lt;br /&gt;&lt;i&gt;(photo by &lt;a href=&quot;https://unsplash.com/@ewitsoe?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Erik Witsoe&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Shared test utilities and test data inevitably become as complex as the code itself when you handle every possible input combination. Recreating a utility for a single purpose in each test means the code is simpler and completely independent from any other test.&lt;/p&gt;

&lt;p&gt;Note, there is a difference between a shared utility and a function shared by similar tests within the same test class. Here the scope is localized and the usage specific, not generic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It’s OK to repeat test utilities &amp;amp; data. Above all, we want to avoid breaking Test A when someone modifies a shared utility so that it works with Test B.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;3-test-your-tests&quot;&gt;3. Test Your Tests&lt;/h1&gt;

&lt;p&gt;A common pitfall is to write tests that return false positives. It is necessary to satisfy two things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Your tests &lt;strong&gt;pass when code is correct&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Your tests &lt;strong&gt;fail when code is incorrect&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This sounds so obvious, but so many times I’ve broken code only to find an existing unit test still passes. 😢&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://clean-swift.com/step-by-step-walkthrough-of-ios-test-driven-development-in-swift/&quot;&gt;TDD&lt;/a&gt; is an obvious antidote to this problem. Consider that tests are the specifications of what your code must do. It seems obvious that you would write the specifications before you implement them. In this way you will see the failing test when code is incomplete, and the passing test only when code is complete. If your test passes before you’ve finished implementing the functionality, it will likely return false positives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You should always run a test twice, once to see it pass, and once to see it fail&lt;/strong&gt;.&lt;/p&gt;

&lt;h1 id=&quot;4-test-naming&quot;&gt;4. Test Naming&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/2020-01-16-The-Right-Unit-Test/chuttersnap-names-unsplash.jpg&quot; alt=&quot;Names are important&quot; /&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;b&gt;Names are important&lt;/b&gt;&lt;br /&gt;&lt;i&gt;(photo by &lt;a href=&quot;https://unsplash.com/@chuttersnap?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;chuttersnap&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Ideally, when a test fails, the name of the test should be all a developer needs to pinpoint the problem in code. Compare two different test names for the same test:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testMyMethodResponses()&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_myMethod_withFriday_returnsSmile()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testMyMethodResponses()&lt;/code&gt; fails, we know that some  &lt;em&gt;myMethod&lt;/em&gt; responses are not correct. We will need to analyse the test and the failing assert before we can start debugging &lt;em&gt;myMethod&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_myMethod_withFriday_returnsSmile()&lt;/code&gt; fails, the test name alone tells us:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The method being tested: &lt;em&gt;myMethod&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;The input being tested: &lt;em&gt;Friday&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;The expected output: &lt;em&gt;Smile&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Given a test name, we should be able to determine which method is being tested, in which state, and what is the expected output/behaviour.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;5-test-coverage&quot;&gt;5. Test Coverage&lt;/h1&gt;

&lt;p&gt;Think about the term &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test coverage&lt;/code&gt; literally. Not with percentages, but imagine that your tests are little green ants swarming all over your class.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/2020-01-16-The-Right-Unit-Test/vlad-tchompalov-green-ant-unsplash.jpg&quot; alt=&quot;That's one test...&quot; /&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;b&gt;That's one test...&lt;/b&gt;&lt;br /&gt;&lt;i&gt;(photo by &lt;a href=&quot;https://unsplash.com/@tchompalov?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Vlad Tchompalov&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;As soon as one of the ants finds something wrong with the class, it will turn red. We want to write lots of small, independent tests that act like status lights, quickly identifying precisely which part of our functionality is broken.&lt;/p&gt;

&lt;p&gt;If all the ants were to turn red at the same time, they would not help pinpoint which functionality is broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In an ideal world, a single bug will cause one (and only one) test to fail, giving us precise information about where and how the bug occurs.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;6-code-safety&quot;&gt;6. Code Safety&lt;/h1&gt;

&lt;p&gt;If we continue the ant analogy, the sweetest parts of each class should have the most ants (🍰 ❤️ 🐜🐜🐜). That is, you should focus your testing on methods that are more &lt;em&gt;safety critical&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What does &lt;em&gt;safety critical&lt;/em&gt; code mean? Focus on testing the parts of your class that &lt;em&gt;could&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ireversibly lose user data/progress&lt;/li&gt;
  &lt;li&gt;Enter an unrecoverable state&lt;/li&gt;
  &lt;li&gt;Compromise user’s private data/security&lt;/li&gt;
  &lt;li&gt;Affect a user’s wallet (banking/buying online)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Prioritise writing tests for safety critical code.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;7-fail-clearly&quot;&gt;7. Fail Clearly&lt;/h1&gt;

&lt;p&gt;When causing a newly written test to fail, it’s important to think how that failure will look to a new pair of eyes. Consider a decodable struct with three variables that are all optional strings. It’s tempting, and quite simple to write one test:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;func test_decodes_fullValidJSON_allFieldsDecoded() {
    let json = &quot;&quot;&quot;
                {
                  &quot;string1&quot;: &quot;This is string1&quot;,
                  &quot;string2&quot;: &quot;This is string2&quot;,
                  &quot;string3&quot;: &quot;This is string3&quot;
                }
               &quot;&quot;&quot;
    let expected = MyStruct(string1: &quot;This is string1&quot;,
                            string2: &quot;This is string2&quot;,
                            string3: &quot;This is string3&quot;)

    guard let jsonData = json.data(using: .utf8) else {
        XCTFail(&quot;Invalid JSON test data&quot;)
        return
    }
    do {
        let decoded = try JSONDecoder().decode(MyStruct.self, from: jsonData)
        XCTAssertEqual(decoded, expected)
    } catch {
        XCTFail(&quot;Could not decode JSON into MyStruct&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The test name is clear and the test is well isolated. However, what happens when the test fails?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;XCTAssertEqual failed: (&quot;MyStruct(string1: Optional(&quot;This is string1.&quot;), string2: Optional(&quot;This is
string2.&quot;), string3: Optional(&quot;This is string3.&quot;))&quot;) is not equal to (&quot;MyStruct(string1: Optional(&quot;
This is string1,&quot;), string2: Optional(&quot;This is string2.&quot;), string3: Optional(&quot;This is string3.&quot;))&quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is a trivial example but I’ve seen tests where the failure takes up half the screen, and requires opening a diff tool to figure out which property failed the equality test.&lt;/p&gt;

&lt;p&gt;The solution is to break this test up into 3 smaller tests, one per field. This would look like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;func test_decodes_string1() {
    let json = &quot;&quot;&quot;
                {
                  &quot;string1&quot;: &quot;This is string1.&quot;,
                }
               &quot;&quot;&quot;
    let expected = MyStruct(string1: &quot;This is string1,&quot;)

    guard let jsonData = json.data(using: .utf8) else {
        XCTFail(&quot;Invalid JSON test data&quot;)
        return
    }
    do {
        let decoded = try JSONDecoder().decode(MyStruct.self, from: jsonData)
        XCTAssertEqual(decoded.string1, expected.string1)
    } catch {
        XCTFail(&quot;Could not decode JSON into MyStruct&quot;)
    }
}

...

func test_decodes_string3() {
  ...
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And the corresponding assertion failure:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;XCTAssertEqual failed: (&quot;Optional(&quot;This is string1.&quot;)&quot;) is not
equal to (&quot;Optional(&quot;This is string1,&quot;)&quot;) -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Ensure that test &lt;em&gt;failures&lt;/em&gt; are trivial to understand. It’s better to write lots of simple tests than one complex test.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;Writing tests is not about quantity, it’s about quality. Essentially we are writing documentation, or specifications, for our future selves;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Here are some examples of how my class should work. If you refactor, or add features to the class, these examples should still pass. If the class functionality changes, some of these examples should break.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/2020-01-16-The-Right-Unit-Test/pierre-bamin-quality-pocket-watch-unsplash.jpg&quot; alt=&quot;Quality tests save you time&quot; /&gt;&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;b&gt;Quality tests save you time&lt;/b&gt;&lt;br /&gt;&lt;i&gt;(photo by &lt;a href=&quot;https://unsplash.com/@bamin?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Pierre Bamin&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;When a developer treats their tests as a second class citizen, their tests will be second class. It’s that simple. You should be as proud of your tests as your production code. Put the time in to make your unit tests great. Just as great code is easy to extend, great tests are easy to augment.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Try to keep your tests to 10 logical statements or fewer!&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;It’s OK to repeat test utilities &amp;amp; data. Above all, we want to avoid breaking Test A when someone modifies a shared utility for Test B&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;You should always run a test twice, once to see it pass, and once to see it fail&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Given a test name, we should be able to determine which method is being tested, in which state, and what is the expected output/behaviour&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;In an ideal world, a single bug will cause one (and only one) test to fail, giving us precise information about where and how the bug occurs&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Prioritise writing tests for safety critical code&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Ensure that test &lt;em&gt;failures&lt;/em&gt; are trivial to understand. It’s better to write lots of simple tests than one complex test&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;After 6 months, is it trivial to understand how your test works?&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;If the answer is no, you’ve written a low quality test. Try again! 😄&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt; &lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Comments? Contact me on &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Twitter&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A special thanks to my former colleague, friend and testing guru Rich Moult for teaching me so much about unit testing.&lt;/em&gt; 🙏&lt;/p&gt;</content><author><name></name></author><summary type="html">This isn’t a post to teach the basics of unit testing on iOS. It’s designed for people who already write unit tests, but aren’t sure if they’re doing it right.</summary></entry><entry><title type="html">A More Diverse iOS Community</title><link href="https://kenthumphries.github.io/a-more-diverse-ios-community/" rel="alternate" type="text/html" title="A More Diverse iOS Community" /><published>2019-12-13T00:00:00+00:00</published><updated>2019-12-13T00:00:00+00:00</updated><id>https://kenthumphries.github.io/a-more-diverse-ios-community</id><content type="html" xml:base="https://kenthumphries.github.io/a-more-diverse-ios-community/">&lt;p&gt;I wrote a blog post for &lt;em&gt;InsideN26&lt;/em&gt; magazine: &lt;a href=&quot;https://medium.com/insiden26/a-more-diverse-ios-community-9c0aefea3015&quot;&gt;A More Diverse iOS Community&lt;/a&gt;. 
&lt;br /&gt;
It’s about our efforts at N26 towards increasing gender diversity within the Berlin iOS community.&lt;/p&gt;</content><author><name></name></author><summary type="html">I wrote a blog post for InsideN26 magazine: A More Diverse iOS Community. It’s about our efforts at N26 towards increasing gender diversity within the Berlin iOS community.</summary></entry><entry><title type="html">Der Berliner Jäger \ The Berlin Hunter</title><link href="https://kenthumphries.github.io/Der-Berliner-Jager/" rel="alternate" type="text/html" title="Der Berliner Jäger \ The Berlin Hunter" /><published>2018-08-19T00:00:00+00:00</published><updated>2018-08-19T00:00:00+00:00</updated><id>https://kenthumphries.github.io/Der-Berliner-Jager</id><content type="html" xml:base="https://kenthumphries.github.io/Der-Berliner-Jager/">&lt;p&gt;This is a 3 part series about my recent job hunting experience in Berlin. I’ve definitely lead more interviews than I’ve taken, so these tips come from both sides of the interview panel.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;Part-1&quot;&gt;Part 1 - Working in Berlin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;Part-2&quot;&gt;Part 2 - No Bullshit.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;Part-3&quot;&gt;Part 3 - Decisions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;my-hunting-tips&quot;&gt;My Hunting Tips&lt;/h3&gt;
&lt;p&gt;Here’s a summary of my iOS job hunting advice:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Update your &lt;a href=&quot;https://kenthumphries.github.io/assets/SampleResume2018.pdf&quot;&gt;resume&lt;/a&gt; and trim any outdated (less relevant) experience&lt;/li&gt;
  &lt;li&gt;In your &lt;a href=&quot;https://kenthumphries.github.io/assets/SampleCoverLetter.pdf&quot;&gt;cover letter&lt;/a&gt;, write &lt;strong&gt;enthusastically&lt;/strong&gt; about why you want to work at the company&lt;/li&gt;
  &lt;li&gt;Over prepare for interviews
    &lt;ul&gt;
      &lt;li&gt;Study up on iOS basics - &lt;a href=&quot;https://medium.com/@duruldalkanat/ios-interview-questions-13840247a57a&quot;&gt;iOS Interview Questions&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Complete simple coding exercises - &lt;a href=&quot;https://www.hackerrank.com&quot;&gt;HackerRank&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;Practice long answer* questions &lt;strong&gt;out loud&lt;/strong&gt;
        &lt;ol&gt;
          &lt;li&gt;Tell us about your previous work experience&lt;/li&gt;
          &lt;li&gt;Why should we hire you?&lt;/li&gt;
          &lt;li&gt;Why do you want to work here?&lt;/li&gt;
          &lt;li&gt;Tell us about a difficult interaction with a colleage&lt;/li&gt;
          &lt;li&gt;Describe a challenging engineering problem you resolved&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Practice describing your career experience out loud, as a story. Ensure this is a compelling story that concludes with the company&lt;/li&gt;
  &lt;li&gt;Revise your &lt;a href=&quot;https://kenthumphries.github.io/assets/SampleCoverLetter.pdf&quot;&gt;cover letter&lt;/a&gt; and &lt;a href=&quot;https://kenthumphries.github.io/assets/SampleResume2018.pdf&quot;&gt;resume&lt;/a&gt; before each interview - this will be your interviewer’s primary reference&lt;/li&gt;
  &lt;li&gt;Reiterate your genuine enthusiasm at each step of the process&lt;/li&gt;
  &lt;li&gt;Plan questions that you want to ask the interviewers
    &lt;ul&gt;
      &lt;li&gt;If you genuinely have none, explain why, rather than flounder for one&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Continue reading: &lt;a href=&quot;Part-1&quot;&gt;Part 1 - Working in Berlin&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Comments? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">This is a 3 part series about my recent job hunting experience in Berlin. I’ve definitely lead more interviews than I’ve taken, so these tips come from both sides of the interview panel.</summary></entry><entry><title type="html">Embedding a Debug Only Framework</title><link href="https://kenthumphries.github.io/Embed-Debug-Framework/" rel="alternate" type="text/html" title="Embedding a Debug Only Framework" /><published>2018-05-01T00:00:00+00:00</published><updated>2018-05-01T00:00:00+00:00</updated><id>https://kenthumphries.github.io/Embed-Debug-Framework</id><content type="html" xml:base="https://kenthumphries.github.io/Embed-Debug-Framework/">&lt;p&gt;When using &lt;a href=&quot;https://docs.fastlane.tools/getting-started/ios/screenshots/&quot;&gt;fastlane/Snapshot&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/shinydevelopment/SimulatorStatusMagic&quot;&gt;SimulatorStatusMagic&lt;/a&gt; (which are both ace!!) to produce screenshots, how should SimulatorStatusMagic be added to a project?&lt;/p&gt;

&lt;h2 id=&quot;just-use-a-dependency-manager&quot;&gt;Just Use a Dependency Manager&lt;/h2&gt;
&lt;p&gt;Alright - that’s the easy way out. Continue reading if your project is not using CocoaPods or Carthage.&lt;/p&gt;

&lt;h2 id=&quot;just-throw-it-in&quot;&gt;Just Throw It In&lt;/h2&gt;
&lt;p&gt;The SimulatorStatusMagic &lt;a href=&quot;https://github.com/shinydevelopment/SimulatorStatusMagic/blob/master/INSTALLATION.md&quot;&gt;installation instructions&lt;/a&gt; outline how to build the framework and add it to your project without a dependency manager.&lt;/p&gt;

&lt;p&gt;Embedding the build works fine for both Debug and Release builds. However, &lt;strong&gt;SimulatorStatusMagic cannot be submitted to Apple in an app binary&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The framework does not contain bitcode. I unwisely &lt;a href=&quot;https://github.com/shinydevelopment/SimulatorStatusMagic/pull/59&quot;&gt;tried to add bitcode&lt;/a&gt; - let’s not talk about that anymore.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The framework contains non-public APIs which are detected by Apple’s automatic code scan.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;  
&lt;img src=&quot;https://kenthumphries.github.io/assets/non-public-apis.png&quot; alt=&quot;Apple's email about non-public APIs&quot; /&gt;
 &lt;/p&gt;

&lt;p&gt;Alas, there is no built-in Xcode mechanism for linking a framework against Debug builds, while excluding Release builds.&lt;/p&gt;

&lt;h2 id=&quot;just-embed-it-for-debug&quot;&gt;Just Embed It For Debug&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Update: I added to the &lt;a href=&quot;https://github.com/shinydevelopment/SimulatorStatusMagic/blob/master/INSTALLATION.md&quot;&gt;official installation instructions on GitHub&lt;/a&gt; to describe this process.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Custom Run Script build phases allow for the embedding of a framework under specified conditions, such as Debug configuration only.&lt;/p&gt;

&lt;p&gt;The Framework must be added to the Framework Search Paths so it can be found at linking time. For example, if the framework is inside a folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThirdPartyFrameworks&lt;/code&gt;, then set:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;
Framework Search Paths-&amp;gt;Debug: $(SRCROOT)/ThirdPartyFrameworks/
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I created a script that embeds a framework only if the build configuration is set to Debug. &lt;a href=&quot;https://gist.github.com/kenthumphries/cf04683184217c7331f9c213c556c65a&quot;&gt;Download it here&lt;/a&gt; with full usage instructions. Hopefully, &lt;em&gt;It Just Works&lt;/em&gt;™.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/custom-run-script-build-phase.png&quot; alt=&quot;Configured run script build phase&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The script solution was adapted from this &lt;a href=&quot;https://stackoverflow.com/a/40484337/9051514&quot;&gt;SO post&lt;/a&gt; which shows how to embed framework for certain architectures.&lt;/p&gt;

&lt;h2 id=&quot;just-embed-it-in-the-uitest-target&quot;&gt;Just Embed It In the UITest Target&lt;/h2&gt;

&lt;p&gt;The above solution allows &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SDStatusBarManager&lt;/code&gt; to be called from within the main app target. When using fastlane/Snapshot, the screenshots are captured from a UITest target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it possible to use SimulatorStatusMagic from the UITest target and keep the app target clean from ‘Debug frameworks’?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yep.&lt;/p&gt;

&lt;p&gt;But it’s a little tricky. There are three players involved when running UITests; the UITest bundle, the app itself, and an Apple generated test runner app.&lt;/p&gt;

&lt;h4 id=&quot;the-uitest-bundle&quot;&gt;The UITest Bundle&lt;/h4&gt;

&lt;p&gt;The test bundle doesn’t actually run - it merely contains the tests for the test runner to perform on the app itself.&lt;/p&gt;

&lt;p&gt;However, it does need to be compiled against the framework, so update the UITest target build settings: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Framework Search Paths: $(SRCROOT)/ThirdPartyFrameworks/&lt;/code&gt;&lt;/p&gt;

&lt;h4 id=&quot;the-app-itself&quot;&gt;The App Itself&lt;/h4&gt;

&lt;p&gt;The app itself does not require the framework to compile. It does require the framework to run, because it’s performing a UITest which calls SimulatorStatusMagic.&lt;/p&gt;

&lt;p&gt;In the UITest target, add a custom Run Script build phase to embed the framework into the app (do insert the red underlined name):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/embed-in-main-app.png&quot; alt=&quot;Configured run script build phase for main app&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;the-generated-test-runner&quot;&gt;The Generated Test Runner&lt;/h4&gt;

&lt;p&gt;The test runner also requires the framework to run.&lt;/p&gt;

&lt;p&gt;In the UITest target, add a custom Run Script built phase to embed the framework in the test runner (do insert the red underlined name):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/embed-in-test-runner.png&quot; alt=&quot;Configured run script build phase for test runner&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Comments? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">When using fastlane/Snapshot &amp;amp; SimulatorStatusMagic (which are both ace!!) to produce screenshots, how should SimulatorStatusMagic be added to a project?</summary></entry><entry><title type="html">Big Fat Initializers</title><link href="https://kenthumphries.github.io/Big-Fat-Initializers/" rel="alternate" type="text/html" title="Big Fat Initializers" /><published>2017-03-01T00:00:00+00:00</published><updated>2017-03-01T00:00:00+00:00</updated><id>https://kenthumphries.github.io/Big-Fat-Initializers</id><content type="html" xml:base="https://kenthumphries.github.io/Big-Fat-Initializers/">&lt;p&gt;A dicsussion about whether you really want to build that big, fat initializer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ugh, gross. Big, fat, bloated inits. They’re about as cool as these dorky tab bars. Just give me a fat hamburger menu and a skinny init. With a side of customisable properties please. Let me configure my object in the state I want, and ignore the properties that I don’t care about. It’s 2011, I think I know what I’m doing…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;cough….ahem&amp;gt;&lt;/p&gt;

&lt;h2 id=&quot;i-like-big-inits-and-i-can-not-lie&quot;&gt;I Like Big Inits, And I Can Not Lie&lt;/h2&gt;

&lt;p&gt;Turns out that I find big, fat initializers way sexier in 2017 than I did in 2011.&lt;/p&gt;

&lt;p&gt;Unthinkingly, I used the term ‘big, fat inits’ in a recent email thread. I was explaining that a detailed init could provide us with a lot of benefits, where the only side effect is having to create a ‘big, fat initializer’. I wish I hadn’t made this sound like a bad thing. I wish I’d used the term ‘deterministic, reliable initializer’ instead.&lt;/p&gt;

&lt;p&gt;The more I write in Swift and think about &lt;a href=&quot;https://developer.apple.com/swift/blog/?id=10&quot;&gt;value types&lt;/a&gt; and immutability, the more I appreciate injecting state at initialization. Make objects as immutable as possible and create objects that behave in fewer, more deterministic ways. The smaller surface area that your state has, the less likely that two instances of the same class can perform in unexpected ways.&lt;/p&gt;

&lt;h2 id=&quot;how-big-is-too-big&quot;&gt;How Big Is Too Big?&lt;/h2&gt;

&lt;p&gt;If your initializer really is getting too big, there are a couple of solutions.&lt;/p&gt;

&lt;p&gt;One symption of big initializers is too many responsibilities. If your object is trying to do many things, it will likely require many dependencies to be injected. Think of ways to cut back your objects responsibilities. Could the responsibilities be split amongst multiple objects? Is there a design pattern that could improve your architecture?&lt;/p&gt;

&lt;p&gt;If your object’s initializer is large because of many related state variables, consider creating a container class. In Swift this would be a value type - an immutable collection of properties that are simpler to pass around as a group. Do not use a dictionary - I guarantee someone will mistype one of your carefully named keys.&lt;/p&gt;

&lt;h2 id=&quot;init-got-back&quot;&gt;Init Got Back!&lt;/h2&gt;

&lt;p&gt;In summary, some advantages to using a deterministic, reliable initializer:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Immutability&lt;/strong&gt;&lt;br /&gt;
Move towards immutable objects (the power of value types in swift) so that an object will behave in a well defined way for it’s entire lifetime.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Clear interface&lt;/strong&gt;&lt;br /&gt;
The init shows which parameters (variables or dependencies) are required to make your object function correctly. Ideally, tend towards &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nonnull&lt;/code&gt; parameters.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Resist Multiple Responsibilities&lt;/strong&gt;&lt;br /&gt;
Declaring all dependencies/state in one place makes it easier to identify a class that is taking on too many responsibilities.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And finally, the disadvantages:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Can’t Think Of Any&lt;/strong&gt;&lt;br /&gt;
Stop supporting countless states, with countless properties, with countless bugs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Want to talk about big, fat initializers? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PS. We have enough real world problems in 2017, please stop using hamburger menus.&lt;/p&gt;</content><author><name></name></author><summary type="html">A dicsussion about whether you really want to build that big, fat initializer.</summary></entry><entry><title type="html">Turn Me On Turn Me Off</title><link href="https://kenthumphries.github.io/Turn-me-on-Turn-me-off/" rel="alternate" type="text/html" title="Turn Me On Turn Me Off" /><published>2017-02-07T00:00:00+00:00</published><updated>2017-02-07T00:00:00+00:00</updated><id>https://kenthumphries.github.io/Turn-me-on-Turn-me-off</id><content type="html" xml:base="https://kenthumphries.github.io/Turn-me-on-Turn-me-off/">&lt;p&gt;General advice for when and how to hide features behind a toggle.&lt;/p&gt;

&lt;p&gt;In an ideal world every feature we write is bite sized and shippable. When development is complete, we get our little featureling a ticket on the next release train and we move on. We are content that our hard work will soon be in the hands of happy users.&lt;/p&gt;

&lt;p&gt;Alas, the real world is not ideal. There are epics and rewrites and features with creepin scopes. There are releases that simply &lt;strong&gt;must go out&lt;/strong&gt; and cannot wait for all features to be completed. At this point there are two common options:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a long lived feature (or epic) branch&lt;/li&gt;
  &lt;li&gt;a toggle that enables the feature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my experience &lt;strong&gt;long lived feature branches&lt;/strong&gt; tend to get muddy. Someone adds a terrific utility that everyone wants on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; and after a cherry pick or two our branches become entangled.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;toggle&lt;/strong&gt; makes life simpler. We can merge everything onto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; and share the benefits. The risk is that features are not properly toggled and incomplete work slips into the hands of our users.&lt;/p&gt;

&lt;h2 id=&quot;toggle-time&quot;&gt;Toggle Time&lt;/h2&gt;
&lt;p&gt;How can we make sure that toggles are safe and effective? Here are some tips.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Aim for one toggle&lt;/strong&gt;&lt;br /&gt;
A toggle that enables/disables all unfinished features reduces possible test states. &lt;em&gt;Wait did you test with feature A on, but feature B off?&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Make the toggle OFF by default&lt;/strong&gt;&lt;br /&gt;
Toggling unfinished features on should always be a conscious act.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Disable the toggle in release builds&lt;/strong&gt;&lt;br /&gt;
Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#ifdef DEBUG&lt;/code&gt; or your own compiler flag so that the toggle is &lt;em&gt;not even compiled&lt;/em&gt; into a release.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Control the toggle from a single point&lt;/strong&gt;&lt;br /&gt;
A well architected toggle should enable/disable a feature as early as possible so that code is not riddled with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if (featureEnabled)&lt;/code&gt; statements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Don’t let the toggle become part of the furniture&lt;/strong&gt;&lt;br /&gt;
Make the toggle control stand out!! Make it hurt your eyeballs!!&lt;br /&gt;
If the toggle is hidden under four layers of submenus*, or nestled in amongst regular controls, it may sneak onto that release train unnoticed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Backup the toggle with a remote kill-switch&lt;/strong&gt;&lt;br /&gt;
The above points all relate to development toggles.&lt;br /&gt;
Add an extra layer of security by adding a remote toggle that can disable or enable a feature without changing the code.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;*If your app has four layers of submenus, you have bigger problems than toggles…&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;remote-toggling&quot;&gt;Remote Toggling&lt;/h2&gt;

&lt;p&gt;A remote toggle can be a value returned in a server response, eg `supportsFeatureX, or something enabled using an A/B testing tool. These remote toggles allow us to perform a staged roll out, or roll back a feature that is not working as expected out in the wild.&lt;/p&gt;

&lt;p&gt;A development toggle and a remote toggle can work well together. Consider the point in the code where the remote toggle is introduced. For a server response, this is likely the parsing code. For an A/B tool this is likely some kind of if statement. Use this point for the development toggle also.&lt;/p&gt;

&lt;p&gt;Think of the development toggle as a hack that allows us to force or circumvent the remote toggle:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When the development toggle is disabled (or removed), the remote toggle is solely responsible for enabling the new feature&lt;/li&gt;
  &lt;li&gt;When the development toggle is enabled, the remote toggle is ignored, and the new feature is enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Feeling passionate about toggles? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">General advice for when and how to hide features behind a toggle.</summary></entry><entry><title type="html">Protocol Extensions - The Bad, the Good and the Ugly</title><link href="https://kenthumphries.github.io/Protocol-Extensions/" rel="alternate" type="text/html" title="Protocol Extensions - The Bad, the Good and the Ugly" /><published>2016-08-15T00:00:00+00:00</published><updated>2016-08-15T00:00:00+00:00</updated><id>https://kenthumphries.github.io/Protocol-Extensions</id><content type="html" xml:base="https://kenthumphries.github.io/Protocol-Extensions/">&lt;p&gt;An experiment with protocol extensions that goes frustratingly wrong.&lt;/p&gt;

&lt;h2 id=&quot;spoilers&quot;&gt;Spoilers&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;The Ugly solution is the best.&lt;/li&gt;
  &lt;li&gt;Protocol extensions won’t work for optional methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;update&quot;&gt;Update&lt;/h4&gt;
&lt;p&gt;Xcode 8 beta 5 shows that Swift 3 helpfully gives a warning about optional methods in a protocol extension:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/obcj-warning.png&quot; alt=&quot;@objc Warning&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-bad&quot;&gt;The Bad&lt;/h2&gt;

&lt;p&gt;The Bad in this post is life before protocol extensions. I’m a big fan of the WWDC 2015 session introducing &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2015/408&quot;&gt;Protocol Oriented Programming&lt;/a&gt; (POP). I remember being blown away when I saw it. I watched it again when I got home, and then again when I started doing more Swift development.&lt;/p&gt;

&lt;p&gt;The primary feature that enables POP is the extension of protocols. In essence, protocol extensions are powerful because they let us provide a default implementation for a protocol. I’m going to talk about a real world use case I came across.&lt;/p&gt;

&lt;h4 id=&quot;my-issue&quot;&gt;My Issue&lt;/h4&gt;
&lt;p&gt;I was trying to create the simplest possible UICollectionViewDelegate that implemented a focus functionality.
Briefly, this functionality is intended to focus on a particular cell after rotating the device:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The first cell that was selected &lt;em&gt;and&lt;/em&gt; visible prior to the rotation, or, failing that&lt;/li&gt;
  &lt;li&gt;The first cell that was mostly visible prior to the rotation&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-bad-solution&quot;&gt;The Bad Solution&lt;/h4&gt;

&lt;p&gt;Let’s take a look at the relevant parts of the code that achieve this (&lt;a href=&quot;https://github.com/kenthumphries/KHCollectionViewTest/blob/TheBad/CollectionViewTest/SimpleDelegate.swift&quot;&gt;here’s the complete file&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We create a concrete delegate that implements UICollectionViewDelegate and store which indexPath was last ‘focussed on’.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class SimpleDelegate: NSObject, UICollectionViewDelegate {
    var selectedIndexPath = NSIndexPath(forItem: 0, inSection: 0)
    var focussedIndexPath = NSIndexPath(forItem: 0, inSection: 0)
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We need to keep the focussedIndexPath up to date following any scrolling events&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
  if !decelerate {
    self.scrollViewDidEndScrolling(scrollView)
  }
}

func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    self.scrollViewDidEndScrolling(scrollView)
}

func scrollViewDidEndScrolling(scrollView: UIScrollView) {

    guard let collectionView = scrollView as? UICollectionView,
        flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
        return
    }
    
    let visibleIndexPaths = collectionView.sortedIndexPathsForVisibleItems()
    
    for indexPath in visibleIndexPaths {
        if let center = flowLayout.centerForItemAtIndexPath(indexPath) where center &amp;gt; collectionView.contentOffset {
            focussedIndexPath = indexPath
            break;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then any time there is a rotation, we need to return the correct targetContentOffsetForProposedContentOffset (thanks to this &lt;a href=&quot;http://stackoverflow.com/questions/13780138/dynamically-setting-layout-on-uicollectionview-causes-inexplicable-contentoffset&quot;&gt;SO post&lt;/a&gt;).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;func collectionView(collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -&amp;gt; CGPoint {
    
    guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
        return proposedContentOffset
    }
    
    return self.targetContentOffsetForProposedContentOffset(proposedContentOffset, flowLayout: flowLayout)
}

func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, flowLayout: UICollectionViewFlowLayout) -&amp;gt; CGPoint {
    var contentOffset = proposedContentOffset
    
    // Determine whether to focus on selectedIndexPath or scrolledIndexPath
    let indexPathToFocusOn: NSIndexPath
    if let visibleIndexPaths = flowLayout.collectionView?.indexPathsForVisibleItems() where visibleIndexPaths.contains(selectedIndexPath) {
        indexPathToFocusOn = selectedIndexPath
    } else {
        indexPathToFocusOn = focussedIndexPath
    }
    
    if let frame = flowLayout.frameForItemAtIndexPath(indexPathToFocusOn) where frame != CGRectZero {
        let originX = max(0, frame.origin.x - flowLayout.minimumInteritemSpacing)
        let originY = max(0, frame.origin.y - flowLayout.minimumInteritemSpacing)
        contentOffset = CGPointMake(originX, originY)
    }
    
    return contentOffset
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works as expected - you can download the Bad project (Swift 2.2) by checking out &lt;a href=&quot;https://github.com/kenthumphries/KHCollectionViewTest/commit/5b2b2ee8c83df753f87bab4254cefa581bd8270c&quot;&gt;this commit&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-good&quot;&gt;The Good&lt;/h2&gt;

&lt;p&gt;Now although the Bad works, it’s not particularly sexy.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The focusing code is spread throughout a delegate that is doing multiple things&lt;/li&gt;
  &lt;li&gt;Each delegate that wants this ability to focus will need to implement all of the code shown above&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;the-good-solution&quot;&gt;The Good Solution&lt;/h4&gt;

&lt;p&gt;Protocol Extensions!&lt;/p&gt;

&lt;p&gt;With Protocol extensions I can solve both of the above shortcomings.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A single protocol that contains all the code required for focusing&lt;/li&gt;
  &lt;li&gt;Default implementations that provide the functionality for free to any UICollectionViewDelegate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are two parts to the UICollectionViewDelegateFlowLayoutFocusing protocol (&lt;a href=&quot;https://github.com/kenthumphries/KHCollectionViewTest/blob/TheGood/CollectionViewTest/UICollectionViewDelegateFlowLayoutFocusing.swift&quot;&gt;here’s the complete file&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A note on naming - this protocol only applies to UICollectionViews with flow layouts, hence the UICollectionViewDelegateFlowLayout part, and the Focusing suffix to show what this protocol does.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public protocol UICollectionViewDelegateFlowLayoutFocusing: UIScrollViewDelegate, UICollectionViewDelegate,     UICollectionViewDelegateFlowLayout {
    
    var focusedIndexPath: NSIndexPath { get set }
    
    // Must be called by collectionView
    func collectionViewDidEndScrolling(scrollView: UIScrollView)
    func focussedContentOffset(collectionView collectionView: UICollectionView) -&amp;gt; CGPoint?
    // Customisation point
    func indexPathToFocusOn(collectionView collectionView: UICollectionView, flowLayout: UICollectionViewFlowLayout) -&amp;gt; NSIndexPath?
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The protocol definition includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a required variable for tracking which indexPath was last focused&lt;/li&gt;
  &lt;li&gt;two required methods that should be called by the UICollectionViewDelegateFlowLayout&lt;/li&gt;
  &lt;li&gt;a required method that is exposed for customisation (to change the algorithm for choosing which indexPath has focus)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;extension UICollectionViewDelegateFlowLayoutFocusing {
    
    func collectionViewDidEndScrolling(scrollView: UIScrollView) {
        
        guard let collectionView = scrollView as? UICollectionView,
            let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
            return
        }
        
        if let indexPathToFocusOn = self.indexPathToFocusOn(collectionView: collectionView, flowLayout: flowLayout) {
            self.focusedIndexPath = indexPathToFocusOn
        }
    }
    
    func indexPathToFocusOn(collectionView collectionView: UICollectionView, flowLayout: UICollectionViewFlowLayout) -&amp;gt; NSIndexPath? {
        
        var indexPathToFocusOn = self.focusedIndexPath // If a new focus can't be found, default to last focus
        
        let visibleIndexPaths = collectionView.sortedIndexPathsForVisibleItems()
        
        if let selectedIndexPaths = collectionView.indexPathsForSelectedItems(),
            visibleSelectedIndexPath = NSArray(array: visibleIndexPaths).firstObjectCommonWithArray(selectedIndexPaths) as? NSIndexPath {
            // One of the selected cels is visible, so use it for the focus
            indexPathToFocusOn = visibleSelectedIndexPath
        } else {
            // No selected visible cells, find the first cell that's at least half visible
            for indexPath in visibleIndexPaths {
                if let center = flowLayout.centerForItemAtIndexPath(indexPath) where center &amp;gt; collectionView.contentOffset {
                    indexPathToFocusOn = indexPath
                    break;
                }
            }
        }
        
        return indexPathToFocusOn
    }
    
    func focussedContentOffset(collectionView collectionView: UICollectionView) -&amp;gt; CGPoint? {
        
        guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout,
            let frame = flowLayout.frameForItemAtIndexPath(focusedIndexPath) where frame != CGRectZero else {
            return nil
        }
        
        let originX = max(0, frame.origin.x - flowLayout.minimumInteritemSpacing)
        let originY = max(0, frame.origin.y - flowLayout.minimumInteritemSpacing)
        return CGPointMake(originX, originY)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The extension of UICollectionViewDelegateFlowLayoutFocusing protocol allows us to provide default implementations for the required methods. This is really powerful as all the complex logic for focusing on a cell is provided along with the protocol itself.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;extension UICollectionViewDelegate where Self: UICollectionViewDelegateFlowLayoutFocusing{
  
  func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
      
      if !decelerate {
          self.collectionViewDidEndScrolling(scrollView)
      }
  }
  
  func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
      
      self.collectionViewDidEndScrolling(scrollView)
  }
  
  func collectionView(collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -&amp;gt; CGPoint {
      
      guard let focusedPoint = self.focussedContentOffset(collectionView: collectionView) else {
              return proposedContentOffset
      }
      
      return focusedPoint
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And for an added convenience, we can provide default implementations for some optional methods of UICollectionViewDelegate. Note that the extension only applies &lt;em&gt;where Self: UICollectionViewDelegateFlowLayoutFocusing&lt;/em&gt; so these default implementations are scoped to delegates that are also implementing UICollectionViewDelegateFlowLayoutFocusing.&lt;/p&gt;

&lt;p&gt;The only obvious downside to this implementation is that if a delegate overrides any of these methods, the default implementations will not be called and focusing will no longer work. For that reason these methods are as simple as possible - in case this code needs to be included in an overridden version.&lt;/p&gt;

&lt;p&gt;The reward for all this is a UICollectionViewDelegate that is incredibly simple:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class SimpleDelegate: NSObject, UICollectionViewDelegateFlowLayoutFocusing // Ensure that the CollectionView is Focusing
{
    var focusedIndexPath = NSIndexPath(forItem: 0, inSection: 0)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the power of protocol extensions. As we have provided default implementations for all the functionality of UICollectionViewDelegateFlowLayoutFocusing, any delegate can add this functionality by implementing the protocol - simply defining a single focusedIndexPath variable.&lt;/p&gt;

&lt;p&gt;You can download the Good project (Swift 2.2) by checking out &lt;a href=&quot;https://github.com/kenthumphries/KHCollectionViewTest/commit/de5dcc1534a655e425f1f91185bbe56b18392117&quot;&gt;this commit&lt;/a&gt;. But first you should read about the Ugly solution.&lt;/p&gt;

&lt;h2 id=&quot;the-ugly&quot;&gt;The Ugly&lt;/h2&gt;

&lt;p&gt;Now although the Good looks beautiful, and super Swifty, it doesn’t actually work.&lt;/p&gt;

&lt;p&gt;The wrinkle is that we’re implementing optional methods on UICollectionViewDelegate. And in order for Swift to work with Objective-C, &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID284&quot;&gt;all optional methods are declared with the @objc keyword&lt;/a&gt;. This enforced compatibility with objective-C also &lt;a href=&quot;http://stackoverflow.com/a/32611453&quot;&gt;causes our extension to be ignored in Swift&lt;/a&gt;. Essentially, our protocol extension never receives the delegate callbacks.&lt;/p&gt;

&lt;h4 id=&quot;the-ugly-solution&quot;&gt;The Ugly Solution&lt;/h4&gt;

&lt;p&gt;Fewer Protocol Extensions!
Inheritance!&lt;/p&gt;

&lt;p&gt;We can still take advantage of the default implementations for UICollectionViewDelegateFlowLayoutFocusing - these are non-optional methods.&lt;/p&gt;

&lt;p&gt;We need to delete the UICollectionViewDelegate extension 😢 and instead add this code directly to a delegate. &lt;strong&gt;At least we made it as concise as possible!&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class FocusingDelegate: NSObject, UICollectionViewDelegateFlowLayoutFocusing // Ensure that the CollectionView is Focusing
{
    var focusedIndexPath = NSIndexPath(forItem: 0, inSection: 0)
}

// MARK: Call UICollectionViewDelegateFlowLayoutFocusing methods on scrolling or external contentOffset change
extension FocusingDelegate {
    
    func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
            self.collectionViewDidEndScrolling(scrollView)
        }
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        self.collectionViewDidEndScrolling(scrollView)
    }
    
    func collectionView(collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -&amp;gt;     CGPoint {
        return self.focussedContentOffset(collectionView, proposedContentOffset: proposedContentOffset)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This solution is not &lt;em&gt;that Ugly&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And we have two options going forward:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Subclass FocusingDelegate
    &lt;ul&gt;
      &lt;li&gt;This is a neat solution, but could cause issues if a delegate needs to inherit from another class&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Copy the code of FocusingDelegate into any focusing delegate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can download the Ugly project (Swift 2.2) by checking out &lt;a href=&quot;https://github.com/kenthumphries/KHCollectionViewTest/commit/5a6a501d1898c8e5f7930fcc25945b4da61b2a6d&quot;&gt;this commit&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Comments? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">An experiment with protocol extensions that goes frustratingly wrong.</summary></entry><entry><title type="html">Swift Baby Steps</title><link href="https://kenthumphries.github.io/Swift-Baby-Steps/" rel="alternate" type="text/html" title="Swift Baby Steps" /><published>2015-11-09T00:00:00+00:00</published><updated>2015-11-09T00:00:00+00:00</updated><id>https://kenthumphries.github.io/Swift-Baby-Steps</id><content type="html" xml:base="https://kenthumphries.github.io/Swift-Baby-Steps/">&lt;p&gt;A few thoughts on our first step towards a Swift codebase.&lt;/p&gt;

&lt;p&gt;When developers leave a team, you can lose valuable (and often obscure) knowledge of a mature codebase. When developers join a team, it’s a valuable opportunity for new ideas and fresh perspective.&lt;/p&gt;

&lt;p&gt;A recent new recruit brought some much needed vigour to our team, giving us a firm shove in the direction of Swift. We needed a jolt to wake us from our warm, comfortable Objective-C routine.&lt;/p&gt;

&lt;p&gt;We were in the fortunate position of rewriting a standalone piece of work, and were able to settle upon a compromise…&lt;/p&gt;

&lt;h4 id=&quot;we-decided-to-write-tests-in-swift&quot;&gt;We decided to write tests in Swift.&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Maintain Velocity&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Writing Swift tests, which are simpler than the functionality they’re verifying, allows us to start integrating Swift without a noticeable impact on velocity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Learn&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Swift. Is. Fun.&lt;/em&gt; There’s a renewed enthusiasm when discussing the simplest of implementation details. Coding in Swift feels exciting!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Build Confidence&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Swift has many new concepts - even optionals can take a bit of unwrapping. Tests focussed around passing parameters and creating variables (or letting them be constants) allow us to focus on the fundamentals.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Make Testing Sexy&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;97% of developers would rather write tests than new functionality. For the remaining 3%, Swift is a great way to ignite our enthusiasm for test writing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Forward Looking&lt;/li&gt;
  &lt;li&gt;Integrating &lt;em&gt;some&lt;/em&gt; Swift code provides a compelling, concrete motive for adding Swift keywords to Objective-C code (nullability, generics)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re only a few weeks into this Swift experiment, but so far so good!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Comments? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">A few thoughts on our first step towards a Swift codebase.</summary></entry><entry><title type="html">NSDates, NSTimeZones, NSCalendars and NSDateComponents. Oh my.</title><link href="https://kenthumphries.github.io/NSDates-NSTimeZones-NSCalendars-NSDateComponents/" rel="alternate" type="text/html" title="NSDates, NSTimeZones, NSCalendars and NSDateComponents. Oh my." /><published>2015-09-28T00:00:00+00:00</published><updated>2015-09-28T00:00:00+00:00</updated><id>https://kenthumphries.github.io/NSDates-NSTimeZones-NSCalendars-NSDateComponents</id><content type="html" xml:base="https://kenthumphries.github.io/NSDates-NSTimeZones-NSCalendars-NSDateComponents/">&lt;p&gt;Answers to some simple questions about how to handle dates and times across timezones.&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;1) Date AND time? Use NSDate.&lt;/p&gt;

&lt;p&gt;2) Time only? Use NSInteger.&lt;/p&gt;

&lt;p&gt;3) Timezone? Store name as NSString.&lt;/p&gt;

&lt;p&gt;4) Date only? Use NSDateComponents.&lt;/p&gt;

&lt;p&gt;5) - 7) Comparing minutes/hours/days/weeks? Use  &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/#//apple_ref/occ/instm/NSCalendar/components:fromDate:toDate:options:&quot;&gt;NSCalendar components:fromDate:toDate:options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;8) Read &lt;a href=&quot;http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/&quot;&gt;Ole Begemann’s detailed post&lt;/a&gt; about dates and times.&lt;/p&gt;

&lt;p&gt;9) From WWDC2013, watch &lt;a href=&quot;https://developer.apple.com/videos/wwdc/2013/&quot;&gt;Solutions to Common Date and Time Challenges&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;1-whats-the-best-option-to-store-a-time-on-a-specific-date&quot;&gt;1) What’s the best option to store a time on a specific date?&lt;/h3&gt;

&lt;p&gt;This is the principal case where NSDate should be used. The name of this class can be misleading. It’s not just a date, it’s a universal time, the seconds since the &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/#//apple_ref/occ/instp/NSDate/timeIntervalSinceReferenceDate&quot;&gt;new millennium began&lt;/a&gt;. i.e. It’s a date AND a time. It’s an instant in time, and it doesn’t take timezone into account. Timezones are just different ways of representing the same instant in time.&lt;/p&gt;

&lt;p&gt;If you want to store a time on a certain day, this is your best bet.&lt;/p&gt;

&lt;h3 id=&quot;2-what-if-i-only-want-to-store-a-time&quot;&gt;2) What if I only want to store a time?&lt;/h3&gt;

&lt;p&gt;A simple NSInteger is a good bet. Store it as the seconds since midnight:
    seconds + (60 * (minutes + (60 * hours)))&lt;/p&gt;

&lt;h3 id=&quot;3-how-do-i-store-a-timensdate-in-a-certain-timezone&quot;&gt;3) How do I store a time/NSDate in a certain timezone?&lt;/h3&gt;
&lt;p&gt;Best to store the timezone separately, then put them together before you do any relevant calculations (NSCalendar), or display to user (NSDateFormatter). You’ll need to create a tuple with your NSInteger/NSDate and the timezone as an NSString. Storing the timezone name (i.e. “Australia/Melbourne”) as an NSString makes it &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_tz_database_time_zones&quot;&gt;easily human identifiable&lt;/a&gt; and easy to &lt;a href=&quot;https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Reference/Foundation/Classes/NSTimeZone_Class/index.html#//apple_ref/occ/clm/NSTimeZone/timeZoneWithName:&quot;&gt;initialise into an NSTimeZone&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;4-what-if-i-only-want-to-store-a-date-without-a-timezone&quot;&gt;4) What if I only want to store a date without a timezone?&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Do not use NSDate, please. I beg you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Use NSDateComponents and fill the components that are relevant. If you want a day of the week, fill only the &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/#//apple_ref/occ/instp/NSDateComponents/weekday&quot;&gt;weekday&lt;/a&gt; component. If you want a day on a certain year, fill &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/#//apple_ref/occ/instp/NSDateComponents/year&quot;&gt;year&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/#//apple_ref/occ/instp/NSDateComponents/month&quot;&gt;month&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/#//apple_ref/occ/instp/NSDateComponents/day&quot;&gt;day&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;It might seem a bit unwieldy, but it will prevent confusion on everyone’s (&lt;em&gt;that includes &lt;strong&gt;you&lt;/strong&gt;, future me!!&lt;/em&gt;) part. You’re not giving any extra information to the date that can be misused and potentially abused.&lt;/p&gt;

&lt;h3 id=&quot;5-how-do-i-compare-two-dates&quot;&gt;5) How do I compare two dates?&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[NSDate compare:]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;6-smartass-i-meant-how-do-i-figure-out-the-days-between-two-dates&quot;&gt;6) Smartass. I meant, how do I figure out the days between two dates??&lt;/h3&gt;

&lt;p&gt;So you want to know how many days are between the 23rd of June and the 7th of July? Well, &lt;a href=&quot;https://en.wikipedia.org/wiki/Thirty_days_hath_September&quot;&gt;thirty days hath September, April, June&lt;/a&gt;… Just kidding. But you do need to keep in mind that months have different numbers of days and 1 actually comes after 30, or 31, or 28….or sometimes 29. Just use &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/#//apple_ref/occ/instm/NSCalendar/components:fromDate:toDate:options:&quot;&gt;NSCalendar components:fromDate:toDate:options&lt;/a&gt; and let Apple do the maths for you.&lt;/p&gt;

&lt;h3 id=&quot;7-how-do-i-figure-out-the-days-between-two-dates-taking-timezone-into-account&quot;&gt;7) How do I figure out the days between two dates, taking timezone into account?&lt;/h3&gt;

&lt;p&gt;If you’re talking timezones, that means you have a time and a timezone. If you’re talking days, that means you have a date. What’s the best option to store a time on a specific date? How do I store a time (or NSDate) in a certain timezone? All that stuff you learnt before &lt;em&gt;is&lt;/em&gt; useful! Yes, use an NSDate and an NSString containing the timezone name.&lt;/p&gt;

&lt;p&gt;You can create an NSTimeZone using your timezone name, and then an NSCalendar aligned to your timezone. Then use good old &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/#//apple_ref/occ/instm/NSCalendar/components:fromDate:toDate:options:&quot;&gt;NSCalendar components:fromDate:toDate:options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, this will assume that ‘day’ means 24 hours apart. What if you mean “how many sleeps between now and my flight to Toulouse?” where your flight is 8am in the morning, and right now it’s 8pm 2 days before? You want to know it’s 2 sleeps, not 36 hours == 1.5 days == 1 ‘full’ day.&lt;/p&gt;

&lt;p&gt;Modified from &lt;a href=&quot;http://stackoverflow.com/a/28921565&quot;&gt;this SO post&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-(NSInteger)daysFromDate:(NSDate *)lhs toDate:(NSDate *)rhs inTimeZone:(NSString *)timeZoneName
{
    NSDate *lhsStart;
    NSDate *rhsStart;

    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:timeZoneName];
    NSCalendar *cal = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    cal.timeZone = timeZone;

    // These lines are key and ensure days only are taken into account, not hours of the day
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&amp;amp;lhsStart interval:NULL forDate:lhs];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&amp;amp;rhsStart interval:NULL forDate:rhs];

    NSDateComponents *difference = [cal components:NSDayCalendarUnit fromDate:lhsStart toDate:rhsStart options:NULL];

    return difference.day;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: It doesn’t make sense to compare two dates in different timezones, ie how long is it from 8pm in Melbourne to 9pm in London? Choose the timezone the user is most concerned with (likely their device’s current timezone), and compare the dates using that timezone.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Comments? &lt;a href=&quot;https://twitter.com/kentios&quot;&gt;Tweet me&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">Answers to some simple questions about how to handle dates and times across timezones.</summary></entry><entry><title type="html">WhenDo Support</title><link href="https://kenthumphries.github.io/WhenDo-Support/" rel="alternate" type="text/html" title="WhenDo Support" /><published>2001-01-01T00:00:00+00:00</published><updated>2001-01-01T00:00:00+00:00</updated><id>https://kenthumphries.github.io/WhenDo-Support</id><content type="html" xml:base="https://kenthumphries.github.io/WhenDo-Support/">&lt;p&gt;Please send any questions to the email address:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://kenthumphries.github.io/assets/whendo-support-email.png&quot; alt=&quot;Support email address&quot; /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">Please send any questions to the email address:</summary></entry></feed>