<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>annema.me</title>
  <subtitle>This is a longer description about your blog.</subtitle>
  <link href="https://annema.me/feed.xml" rel="self" />
  <link href="https://annema.me/" />
  <updated>2026-04-02T00:00:00Z</updated>
  <id>https://annema.me/</id>
  <author>
    <name>Klaas Pieter Annema</name>
  </author>
  <entry>
    <title>OWE on the GL.iNet Flint 3</title>
    <link href="https://annema.me/blog/owe-on-gl-inet-flint-3/" />
    <updated>2026-04-02T00:00:00Z</updated>
    <id>https://annema.me/blog/owe-on-gl-inet-flint-3/</id>
    <content type="html">&lt;p&gt;For my work at &lt;a href=&quot;https://ipinfo.io&quot;&gt;IPinfo&lt;/a&gt; I needed an open Wi-Fi network to
test against. Having learned of the existence of &lt;a href=&quot;https://en.wikipedia.org/wiki/Opportunistic_Wireless_Encryption&quot;&gt;Opportunistic Wireless
Encryption (OWE)&lt;/a&gt;
and that OpenWrt &lt;a href=&quot;https://openwrt.org/docs/guide-user/network/wifi/owe_encryption&quot;&gt;supports it&lt;/a&gt;, I wanted to have one.&lt;/p&gt;
&lt;p&gt;OWE encrypts traffic on open networks without requiring a password. Clients
(&lt;a href=&quot;https://support.apple.com/en-gb/guide/deployment/dep3b0448c58/web#depa1e03df0e&quot;&gt;Apple&lt;/a&gt;, &lt;a href=&quot;https://source.android.com/docs/core/connect/wifi-wpa3-owe&quot;&gt;Android&lt;/a&gt;) that
support OWE encrypt their traffic. Lack of encryption was always the big drawback of open networks. For my use case it didn&#39;t really matter (I don&#39;t expect anyone to join), but now I get to say I have an encrypted guest Wi-Fi network that doesn&#39;t need a password.&lt;/p&gt;
&lt;p&gt;Setting it up on the &lt;a href=&quot;https://annema.me/blog/configure-gl-inet-gl-be9300-flint-3-on-kpn-fiber/&quot;&gt;Flint 3&lt;/a&gt;
was straightforward following the OpenWrt
&lt;a href=&quot;https://openwrt.org/docs/guide-user/network/wifi/guestwifi/guest-wlan&quot;&gt;guest Wi-Fi&lt;/a&gt; and
&lt;a href=&quot;https://openwrt.org/docs/guide-user/network/wifi/owe_encryption&quot;&gt;OWE&lt;/a&gt; guides.
But it didn&#39;t work. There were two separate issues.&lt;/p&gt;
&lt;h2&gt;GL.iNet firmware bug&lt;/h2&gt;
&lt;p&gt;The OpenWrt guides tell you to set &lt;code&gt;encryption=&#39;owe&#39;&lt;/code&gt; on the wireless interface.
Presumably this works in the normal version of OpenWrt, but there&#39;s a
bug in the modified variant that ships with the Flint 3&#39;s firmware. On firmware 4.8.4 it silently
creates an open network with no encryption. &lt;a href=&quot;https://forum.gl-inet.com/t/owe-silently-broken-on-flint3/67660&quot;&gt;Technical details&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The workaround is to use the encryption and OWE flag separately:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;uci &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; wireless.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;iface&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;.encryption&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ccmp&#39;&lt;/span&gt;
uci &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; wireless.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;iface&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;.owe&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;1&#39;&lt;/span&gt;
uci commit wireless
wifi&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CoreWLAN bug&lt;/h2&gt;
&lt;p&gt;After getting OWE working I noticed that macOS and iOS report the network as &amp;quot;Security:
None&amp;quot;. At first I thought OWE wasn&#39;t working, but checking on the router
confirmed it was.&lt;/p&gt;
&lt;p&gt;The bug is in Apple&#39;s CoreWLAN framework. &lt;code&gt;CWInterface.security()&lt;/code&gt; returns
&lt;code&gt;kCWSecurityNone&lt;/code&gt; (0) for an active OWE connection when it should return
&lt;code&gt;kCWSecurityOWE&lt;/code&gt; (14). The scan API gets it right:
&lt;code&gt;CWNetwork.strongestSupportedSecurity&lt;/code&gt; correctly returns &lt;code&gt;kCWSecurityOWE&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Maybe because of this bug the UI also doesn&#39;t distinguish OWE from open networks
at all. Same appearance and security warning. Anyone who went through the
trouble of setting up OWE gets flagged as insecure anyway. That&#39;s wrong.&lt;/p&gt;
&lt;p&gt;Apple feedback ID: FB22250575&lt;/p&gt;
&lt;h2&gt;Free Wi-Fi for all&lt;/h2&gt;
&lt;p&gt;It took a lot of fiddling and going back and forth with Claude but ultimately I
was able to come up with a solution that I understood and could report issues
for. Finding issues with iOS and macOS was an unexpected bonus. I guess.&lt;/p&gt;
&lt;p&gt;If you&#39;re ever &lt;a href=&quot;https://eemgoed.nl&quot;&gt;near my house&lt;/a&gt; be sure to join my open but encrypted
Wi-Fi.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Configure GL.iNet GL-BE9300 (Flint 3) on KPN fiber</title>
    <link href="https://annema.me/blog/configure-gl-inet-gl-be9300-flint-3-on-kpn-fiber/" />
    <updated>2026-03-17T00:00:00Z</updated>
    <id>https://annema.me/blog/configure-gl-inet-gl-be9300-flint-3-on-kpn-fiber/</id>
    <content type="html">&lt;h2&gt;Backstory&lt;/h2&gt;
&lt;p&gt;Up until a few days ago my main Wi-Fi router was an Apple Time Capsule. It&#39;s one of the latest models but still this thing is &lt;em&gt;old&lt;/em&gt;. Apple discontinued the product line in 2018 but I probably bought it in 2013, maybe 2014. That makes it over 10 years old. It survived 3 NYC apartments, a move back to The Netherlands, being stored in an attic for a while, dusted off and then 2 more houses. The longevity of this thing is honestly amazing (granted I haven&#39;t used it for backups for a few years but when I stopped even the hard drive still worked).&lt;/p&gt;
&lt;p&gt;I didn&#39;t even replace it because it was broken but because I need more configurability for my work at &lt;a href=&quot;https://ipinfo.io&quot;&gt;IPinfo&lt;/a&gt;. To test I occasionally need uncommon network configurations like an IPv6-only network, an open Wi-Fi network or just a separate Wi-Fi network to begin with. None of these were easy to set up on my Time Capsule or the router that came for free with my KPN subscription.&lt;/p&gt;
&lt;h2&gt;UniFi vs GL.iNet&lt;/h2&gt;
&lt;p&gt;For years I thought I would upgrade to &lt;a href=&quot;https://www.ui.com/&quot;&gt;UniFi&lt;/a&gt; but I decided against it. The fact that it&#39;s an American company didn&#39;t work in its favor but ultimately I realized I didn&#39;t need their ecosystem. I run Home Assistant so anything I can get through their ecosystem I can also connect to my current network and have Home Assistant handle it.&lt;/p&gt;
&lt;p&gt;Instead I went for a &lt;a href=&quot;https://store-eu.gl-inet.com/collections/home-routers/products/flint-3-gl-be9300-tri-band-wi-fi-7-home-router&quot;&gt;Flint 3 (GL-BE9300)&lt;/a&gt;. It was recommended by a coworker, it&#39;s well reviewed by &lt;a href=&quot;https://www.rtings.com/router/reviews/gl-inet/flint-3-gl-be9300&quot;&gt;rthings.com&lt;/a&gt; but most importantly it runs a modified &lt;a href=&quot;https://openwrt.org/&quot;&gt;OpenWrt&lt;/a&gt; firmware. I don&#39;t have to set up OpenWrt from scratch but I can still use it to configure unusual network configurations.&lt;/p&gt;
&lt;h2&gt;KPN setup&lt;/h2&gt;
&lt;p&gt;After I received my new router I needed to make it work on my KPN Fiber connection. Initially I followed &lt;a href=&quot;https://danieldk.eu/Hardware/Networking/GL.iNet-GL-MT6000-on-KPN-fiber&quot;&gt;this guide&lt;/a&gt;. In case the guide ever disappears here&#39;s a quick summary of its setup:&lt;/p&gt;
&lt;p&gt;Under “Ethernet 1” click “Modify” then use the following settings:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PPPoE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Username&lt;/td&gt;
&lt;td&gt;&lt;code&gt;internet&lt;/code&gt; (can be anything)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password&lt;/td&gt;
&lt;td&gt;&lt;code&gt;internet&lt;/code&gt; (can be anything)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VLAN ID&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MTU&lt;/td&gt;
&lt;td&gt;1500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Then click “Apply”&lt;/p&gt;
&lt;h2&gt;IPv6 support&lt;/h2&gt;
&lt;p&gt;The guide worked, but left me without IPv6 support. After some digging I found
it&#39;s something I need to enable by going to “Network” -&amp;gt; “IPv6” and then enable
it with the following settings:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mode&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS Acquisition method&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Finally go to “Network” -&amp;gt; “Multi-WAN”, Click the settings gear next to “Ethernet 1” and change “Protocol” from “IPv4” to “Both”&lt;/p&gt;
&lt;p&gt;That&#39;s it. A quick way to test if it worked is to see if &lt;a href=&quot;https://v6.ipinfo.io&quot;&gt;v6.ipinfo.io&lt;/a&gt; loads. Next I&#39;m going to set up an open but encrypted (&lt;a href=&quot;https://en.wikipedia.org/wiki/Opportunistic_Wireless_Encryption&quot;&gt;OWE&lt;/a&gt;) Wi-Fi network for testing.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Get notified when a GitHub action completes</title>
    <link href="https://annema.me/blog/get-notified-gh-action/" />
    <updated>2026-02-12T00:00:00Z</updated>
    <id>https://annema.me/blog/get-notified-gh-action/</id>
    <content type="html">&lt;p&gt;Often I’m waiting to merge a PR until all of its checks have passed. While I do
my best to keep checks as fast as possible they still take long enough that I’m
not going to wait for them to finish. I start something new while I wait.
Frequently I then forget to merge the PR because I’m
completely caught up in the next thing. This is even worse for PRs where
I’m testing changes to the GitHub actions. I have to wait for feedback but then
forget to check when it’s finally there.&lt;/p&gt;
&lt;p&gt;To avoid this, I want to get notified when a GitHub action completes. I know I
can &lt;a href=&quot;https://docs.github.com/en/actions/concepts/workflows-and-actions/notifications-for-workflow-runs&quot;&gt;enable notifications for workflow runs&lt;/a&gt;.
GitHub gives me two options; email and/or web. I manage all my GitHub
notifications through the web UI, so email is out of the question. Enabling workflow
notifications for web just means workflow runs will end up in the GitHub UI. I still have to remember to check which brings me back to the
original problem.&lt;/p&gt;
&lt;p&gt;Luckily the command line and GitHub&#39;s &lt;a href=&quot;https://cli.github.com/&quot;&gt;command line
interface&lt;/a&gt; can help. Now, whenever I need to be notified
of a workflow run I use:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;gh run &lt;span class=&quot;token function&quot;&gt;watch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; terminal-notifier title &lt;span class=&quot;token string&quot;&gt;&quot;CI&quot;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-message&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Run completed&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;gh run watch&lt;/code&gt; prompts for what run to watch and &lt;code&gt;;&lt;/code&gt; will run
&lt;code&gt;terminal-notifier&lt;/code&gt; after &lt;code&gt;gh&lt;/code&gt; finishes regardless of whether it succeeds or
not.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; if you only want to be notified on success or &lt;code&gt;||&lt;/code&gt; for
failures.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Converting ISO country codes to country names using Locale</title>
    <link href="https://annema.me/blog/converting-iso-country-codes-to-country-names-using-locale/" />
    <updated>2025-10-31T00:00:00Z</updated>
    <id>https://annema.me/blog/converting-iso-country-codes-to-country-names-using-locale/</id>
    <content type="html">&lt;p&gt;Because IPinfo&#39;s open API always returns country codes, I needed to convert them to country names for better address formatting. For example, &lt;a href=&quot;https://ipinfo.io/1.1.1.1/json&quot;&gt;1.1.1.1&lt;/a&gt; returns AU for Australia. The authenticated tiers (free &lt;a href=&quot;https://ipinfo.io/developers/lite-api&quot;&gt;Lite&lt;/a&gt; and paid &lt;a href=&quot;https://ipinfo.io/developers/core-api&quot;&gt;Core&lt;/a&gt;/&lt;a href=&quot;https://ipinfo.io/developers/plus-api&quot;&gt;Plus&lt;/a&gt;) have both codes and names, but the open API doesn&#39;t.&lt;/p&gt;
&lt;p&gt;At first I hoped this would do the trick:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; postalAddress &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CNMutablePostalAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
postalAddress&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isoCountryCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ipInfoResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;country
&lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;postalAddress&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;country&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sadly &lt;code&gt;CNPostalAddress&lt;/code&gt; and &lt;code&gt;CNPostalAddressFormatter&lt;/code&gt; don’t map country codes to
country names. While looking for alternatives, I found &lt;a href=&quot;https://gist.github.com/dineybomfim/a4d88330111032e212ef66446d19dbcb&quot;&gt;this gist&lt;/a&gt;. It uses
&lt;code&gt;Locale&lt;/code&gt;’s
&lt;a href=&quot;https://developer.apple.com/documentation/foundation/locale/localizedstring(forregioncode:)&quot;&gt;&lt;code&gt;localizedString(forRegionCode:)&lt;/code&gt;&lt;/a&gt;
to init a &lt;code&gt;Locale&lt;/code&gt; using just the country code. What an incredibly elegant idea!
No external dependencies and just platform native APIs which are much more
likely to return similar results as people would see in Apple’s own apps. Since I only need country names (not a full locale), the code is even shorter:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Locale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;autoupdatingCurrent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localizedString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forRegionCode&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;NL&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Netherlands&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it.&lt;/p&gt;
&lt;p&gt;This almost felt too easy. I was looking forward to building a solution: importing mapping data, handling translations, dealing with edge cases. Instead, one line of platform API code solved it better than anything I could build. Feeling robbed of a good engineering challenge, I decided to verify this simple solution actually works. I tested this against &lt;a href=&quot;https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes&quot;&gt;all ISO-3166 country codes&lt;/a&gt; to see what happens.&lt;/p&gt;
&lt;p&gt;The setup:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes/blob/145f1ad3caff212ed25f42b0ee2c8b92a75af895/slim-2/slim-2.json&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Country&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Decodable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CodingKeys&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CodingKey&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; name
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; alpha2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;alpha-2&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; countryCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;country-code&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; alpha2&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; countryCode&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; decoder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JSONDecoder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; countries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; decoder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Country&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  from&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;using&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utf8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocaleCountry&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; originalName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; locale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Locale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; localeCountries&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;LocaleCountry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; countries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compactMap &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; countryName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; locale&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;localizedString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forRegionCode&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alpha2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token nil constant&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocaleCountry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; countryName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    code&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alpha2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    originalName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Starting with the basics, let’s confirm no countries are missing:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;localeCountries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; countries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then let’s confirm every country has a name:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;localeCountries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isEmpty &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, let’s check if all the names match:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;localeCountries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;originalName &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 49&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I knew this was too easy; I found 49 mismatches. On closer inspection however, the simple solution actually works better than expected. These were mostly stylistic mismatches. For example “BQ” in the original data is “Bonaire,
Sint Eustatius and Saba” whereas Apple uses “Caribbean Netherlands”. Similarly the
original data uses the awkward “Netherlands, Kingdom of the” whereas Apple returns just “Netherlands” which is better. Apple also makes other stylistic choices (like using “&amp;amp;” instead of “and” in Antigua &amp;amp; Barbuda) that feel more natural. By using platform native APIs, we get the same values Apple uses. Which is what users from, for example, the Caribbean Netherlands, Côte d’Ivoire and Netherlands will expect. Although as someone from The Netherlands, I do miss the &lt;em&gt;The&lt;/em&gt; in The Netherlands.&lt;/p&gt;
&lt;p&gt;For reference here’s the full list of mismatches:&lt;/p&gt;
&lt;pre class=&quot;language-plain&quot; data-language=&quot;Plain text&quot;&gt;&lt;code class=&quot;language-plain&quot;&gt;AG: Antigua &amp;amp; Barbuda != Antigua and Barbuda
BO: Bolivia != Bolivia, Plurinational State of
BQ: Caribbean Netherlands != Bonaire, Sint Eustatius and Saba
BA: Bosnia &amp;amp; Herzegovina != Bosnia and Herzegovina
IO: Chagos Archipelago != British Indian Ocean Territory
BN: Brunei != Brunei Darussalam
CV: Cape Verde != Cabo Verde
CN: China mainland != China
CG: Congo - Brazzaville != Congo
CD: Congo - Kinshasa != Congo, Democratic Republic of the
CI: Côte d’Ivoire != Côte d’Ivoire
FK: Falkland Islands != Falkland Islands (Malvinas)
HM: Heard &amp;amp; McDonald Islands != Heard Island and McDonald Islands
VA: Vatican City != Holy See
IR: Iran != Iran, Islamic Republic of
KP: North Korea != Korea, Democratic People’s Republic of
KR: South Korea != Korea, Republic of
LA: Laos != Lao People’s Democratic Republic
FM: Micronesia != Micronesia, Federated States of
MD: Moldova != Moldova, Republic of
MM: Myanmar (Burma) != Myanmar
NL: Netherlands != Netherlands, Kingdom of the
PS: Palestinian Territories != Palestine, State of
PN: Pitcairn Islands != Pitcairn
RU: Russia != Russian Federation
BL: St. Barthélemy != Saint Barthélemy
SH: St. Helena != Saint Helena, Ascension and Tristan da Cunha
KN: St. Kitts &amp;amp; Nevis != Saint Kitts and Nevis
LC: St. Lucia != Saint Lucia
MF: St. Martin != Saint Martin (French part)
PM: St. Pierre &amp;amp; Miquelon != Saint Pierre and Miquelon
VC: St. Vincent &amp;amp; Grenadines != Saint Vincent and the Grenadines
ST: São Tomé &amp;amp; Príncipe != Sao Tome and Principe
SX: Sint Maarten != Sint Maarten (Dutch part)
GS: So. Georgia &amp;amp; So. Sandwich Isl. != South Georgia and the South Sandwich Islands
SJ: Svalbard &amp;amp; Jan Mayen != Svalbard and Jan Mayen
SY: Syria != Syrian Arab Republic
TW: Taiwan != Taiwan, Province of China
TZ: Tanzania != Tanzania, United Republic of
TT: Trinidad &amp;amp; Tobago != Trinidad and Tobago
TC: Turks &amp;amp; Caicos Islands != Turks and Caicos Islands
GB: United Kingdom != United Kingdom of Great Britain and Northern Ireland
US: United States != United States of America
UM: U.S. Outlying Islands != United States Minor Outlying Islands
VE: Venezuela != Venezuela, Bolivarian Republic of
VN: Vietnam != Viet Nam
VG: British Virgin Islands != Virgin Islands (British)
VI: U.S. Virgin Islands != Virgin Islands (U.S.)
WF: Wallis &amp;amp; Futuna != Wallis and Futuna&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>What is bad behavior?</title>
    <link href="https://annema.me/blog/what-is-bad-behavior/" />
    <updated>2025-10-30T00:00:00Z</updated>
    <id>https://annema.me/blog/what-is-bad-behavior/</id>
    <content type="html">&lt;p&gt;During my run I had a discussion in my head about bad behavior. What makes a behavior bad? Why is it bad?&lt;/p&gt;
&lt;p&gt;The discussion in my head started when I ran by an &lt;a href=&quot;https://en.wikipedia.org/wiki/Desire_path&quot;&gt;elephant path&lt;/a&gt; made by people, mostly kids, biking across the grass to get to the main bicycle path. I was annoyed by this because &lt;a href=&quot;https://eemgoed.nl&quot;&gt;my community&lt;/a&gt; has asked people to stop doing it and I talk to my kids about it every time I see them do it. Even though I know they will probably do it anyway if I&#39;m not watching.&lt;/p&gt;
&lt;p&gt;I imagined myself being in the meeting with &lt;a href=&quot;https://en.wikipedia.org/wiki/Staatsbosbeheer&quot;&gt;Staatsbosbeheer&lt;/a&gt; (the Dutch forestry service who owns this area) where the discussion was about potential solutions. The first argument I made in my head was to put up some sort of barrier to prevent the behavior but then I remembered an example from a university. After they renovated the lawn, they purposely didn&#39;t add any paths. Instead they waited a year to see where paths would naturally emerge and added them there.&lt;/p&gt;
&lt;p&gt;That example in mind I began arguing for doing the same. In my head someone else would argue &amp;quot;but that&#39;s rewarding the wrong behavior&amp;quot;. At this point I began questioning what is bad behavior? Why is it bad? I remembered what happened with my oldest after I discovered he had been playing Roblox even though we told him not to. We&#39;d banned it because we worried he wouldn&#39;t come to us if things in the game troubled him.&lt;/p&gt;
&lt;p&gt;He explained that he&#39;d been doing it in secret for some time with his friends. All of his friends are allowed to play Roblox. He was playing games together with them and he was the only one not allowed to play it himself. Is this bad behavior? Was this a child&#39;s form of civil disobedience? Was he challenging a rule that didn&#39;t make sense to him? We eventually decided to let him keep playing Roblox after we explained our fears to him.&lt;/p&gt;
&lt;p&gt;That university asked &amp;quot;what are people trying to tell us?&amp;quot; instead of &amp;quot;how do we stop them?&amp;quot; Maybe that&#39;s the better question.&lt;/p&gt;
&lt;p&gt;Is that condoning his disobedience? Or is it recognizing that the traits that frustrate us now — standing up for himself and questioning authority — are exactly what we want him to have as an adult? What about the university example? Was it bad behavior for people to walk on the grass or was it okay there because there was no other option?&lt;/p&gt;
&lt;p&gt;And finally, what about my initial example? Is putting a path where people obviously want one the same: rewarding rule-breaking? Or is it listening to what people are trying to tell us?&lt;/p&gt;
&lt;p&gt;I don&#39;t know. But I think I&#39;d rather err on the side of flexibility and meet people where they are. Even when it feels like giving in.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Accessing Swift Package Manager dependency versions at runtime</title>
    <link href="https://annema.me/blog/accessing-swift-package-manager-dependency-versions-at-runtime/" />
    <updated>2025-09-28T00:00:00Z</updated>
    <id>https://annema.me/blog/accessing-swift-package-manager-dependency-versions-at-runtime/</id>
    <content type="html">&lt;p&gt;I was building a debug screen for an iOS/Mac app and wanted to display the version of a third-party dependencies managed by Swift Package Manager.&lt;/p&gt;
&lt;p&gt;My first instinct was to use an Xcode &lt;a href=&quot;https://developer.apple.com/documentation/xcode/running-custom-scripts-during-a-build&quot;&gt;run script build phase&lt;/a&gt; to extract version information at build time, but I quickly ran into various code signing errors that made this approach unreliable. Especially because building for macOS triggered code signing errors for different configurations than iOS did. I didn&#39;t look very hard, but I wasn&#39;t able to find a configuration that worked for both platforms.&lt;/p&gt;
&lt;p&gt;After some experimentation, I found a solution that works reliably: copying the &lt;code&gt;Package.resolved&lt;/code&gt; file at build time and parsing it at runtime. The &lt;code&gt;Package.resolved&lt;/code&gt; file contains the exact commit hashes and versions of all your dependencies, so it&#39;s perfect for this use case.&lt;/p&gt;
&lt;p&gt;Here&#39;s how to set it up. First, create a run script build phase that copies the file into your project directory:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${PROJECT_FILE_PATH}&lt;/span&gt;/project.xcworkspace/xcshareddata/swiftpm/Package.resolved &lt;span class=&quot;token variable&quot;&gt;${PROJECT_DIR}&lt;/span&gt;/Package.resolved&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure to add &lt;code&gt;${PROJECT_DIR}/Package.resolved&lt;/code&gt; under Output Files in your run script build phase. This tells Xcode that this file is generated by the script. I don&#39;t know since when but at least in Xcode 26 build scripts run in a sandbox. If you forget to add input and output files Xcode will complain.&lt;/p&gt;
&lt;p&gt;Next, add the copied file to your Xcode project (you can drag it into the project navigator or right-click and select &amp;quot;Add Files to [project name]&amp;quot;). Ensure the file is included in &amp;quot;Copy Bundle Resources&amp;quot; and that your run script build phase runs before the copy resources phase.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Package.resolved&lt;/code&gt; is just JSON, so we can decode it with a simple struct:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// SPM.swift&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foundation&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SPM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Codable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; pins&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Codable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Codable&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; revision&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; identity&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;State&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;allPackages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Package&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;guard&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; packagesPath &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bundle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forResource&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Package&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ofType&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;resolved&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contentsOf&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fileURLWithPath&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; packagesPath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; resolved &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JSONDecoder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SPM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; from&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; resolved&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pins
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;allPackages()&lt;/code&gt; method loads the bundled &lt;code&gt;Package.resolved&lt;/code&gt; file and decodes it into an array of packages. Each package includes its identity (name) and the exact commit revision. If you need other fields, take a look at your &lt;code&gt;Package.resolved&lt;/code&gt; file to see what&#39;s available and add it to the &lt;code&gt;SPM&lt;/code&gt; hierarchy.&lt;/p&gt;
&lt;p&gt;I don&#39;t yet know how reliable this is, but it works fine so far. I later realized it&#39;s the same technique used by &lt;a href=&quot;https://github.com/timroesner/SPM-Acknowledgments&quot;&gt;SPM-Acknowledgments&lt;/a&gt; to auto-generate acknowledgments screens. At the time of writing SPM-Acknowledgments was last updated in &lt;a href=&quot;https://github.com/timroesner/SPM-Acknowledgments/commit/d3270700873c063d8a6bc244cfe7bab0d18533f6&quot;&gt;2020&lt;/a&gt; which suggests that this approach is stable enough. For me it&#39;s for debug information so it&#39;s okay if it stops working.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Moving DNS from Cloudflare to Gandi using DNSControl</title>
    <link href="https://annema.me/blog/move-domains-from-cloudflare-to-ghandi-using-dnscontrol/" />
    <updated>2025-09-24T00:00:00Z</updated>
    <id>https://annema.me/blog/move-domains-from-cloudflare-to-ghandi-using-dnscontrol/</id>
    <content type="html">&lt;h2&gt;Current setup&lt;/h2&gt;
&lt;p&gt;I&#39;m in the process of moving this site to Europe. For the past couple of
years annema.me was hosted on GitHub Pages. My domain registrar was
dotster.com and DNS was done by Cloudflare.&lt;/p&gt;
&lt;h2&gt;Historical context&lt;/h2&gt;
&lt;p&gt;I registered annema.me with Dotster in 2011 because I worked at
&lt;a href=&quot;http://madebysofa.com&quot;&gt;Sofa&lt;/a&gt; and they used Dotster. I later moved to Cloudflare
for DNS since it made HTTPS easy.&lt;/p&gt;
&lt;p&gt;For years all I heard from Dotster was the occasional renewal email, but then
they rebranded to web.com, then Network Solutions, triggering excessive
emails with each change. Combined with wanting to use European providers, this
prompted me to move all my domains.&lt;/p&gt;
&lt;h2&gt;The migration challenge&lt;/h2&gt;
&lt;p&gt;At the moment annema.me is rented through &lt;a href=&quot;https://gandi.net&quot;&gt;gandi.net&lt;/a&gt;
but the DNS is still controlled by Cloudflare. Unfortunately, moving DNS to Gandi without
interruption requires switching to Gandi&#39;s LiveDNS, which provides only a
bare text box for entering existing DNS records. It doesn&#39;t even tell me, a
DNS novice, what format it expects.&lt;/p&gt;
&lt;p&gt;My first attempt was to use Cloudflare&#39;s export and paste the result of that
into the box. It gave a ton of cryptic errors. I tried editing the file because
it complained about Cloudflare&#39;s magic TTL of 1 (which just means Cloudflare
handles TTL automagically). Even changing it to 300, Gandi&#39;s minimum, but none
of that worked.&lt;/p&gt;
&lt;p&gt;Besides this all feels fragile. I honestly don&#39;t care too much if everything
goes down but I at least want to &lt;em&gt;try&lt;/em&gt; to keep things up.&lt;/p&gt;
&lt;p&gt;I don&#39;t remember how I found it, but I ended up using
&lt;a href=&quot;https://dnscontrol.org&quot;&gt;DNSControl&lt;/a&gt; to automate the migration.&lt;/p&gt;
&lt;h2&gt;Exporting existing records&lt;/h2&gt;
&lt;p&gt;After &lt;a href=&quot;https://docs.dnscontrol.org/getting-started/getting-started#id-4.-create-the-initial-creds.json&quot;&gt;setting up my
credentials&lt;/a&gt;
I needed a
&lt;a href=&quot;https://docs.dnscontrol.org/getting-started/getting-started#id-3.-create-the-initial-dnsconfig.js&quot;&gt;&lt;code&gt;dnsconfig.js&lt;/code&gt;&lt;/a&gt;
with my own DNS configuration. Again it felt error prone to do this manually
so I used &lt;code&gt;dnscontrol get-zones&lt;/code&gt; instead:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;dnscontrol get-zones &lt;span class=&quot;token parameter variable&quot;&gt;--out&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;dnsconfig.js &lt;span class=&quot;token parameter variable&quot;&gt;--format&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;djs cloudflare - all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which gives a good starting point:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DSP_CLOUDFLARE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NewDnsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;cloudflare&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REG_CHANGEME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NewRegistrar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token constant&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;annema.me&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;REG_CHANGEME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;DnsProvider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DSP_CLOUDFLARE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;DefaultTTL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;185.199.111.153&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CF_PROXY_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;185.199.110.153&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CF_PROXY_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;185.199.109.153&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CF_PROXY_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token constant&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;185.199.108.153&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;CF_PROXY_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// etc&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The 404 roadblock&lt;/h2&gt;
&lt;p&gt;With that in place I added &lt;code&gt;DSP_GANDI = NewDnsProvider(&amp;quot;gandi&amp;quot;)&lt;/code&gt; and, with the
credentials already configured, ran &lt;code&gt;dnscontrol preview&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$ dnscontrol preview
**&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;***&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;***&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;*** Domain: annema.me
INFO&lt;span class=&quot;token comment&quot;&gt;#1: Domain &quot;annema.me&quot; provider gandi Error: StatusCode: 404 ; Err: 404: Unknown domain&lt;/span&gt;
INFO&lt;span class=&quot;token comment&quot;&gt;#2: DetermineNS: zone &quot;annema.me&quot;; Error: error while getting&lt;/span&gt;
Nameservers &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;annema.me&quot;&lt;/span&gt; with &lt;span class=&quot;token assign-left variable&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;gandi&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; StatusCode: &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Err: &lt;span class=&quot;token number&quot;&gt;404&lt;/span&gt;: Unknown domain&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This confused me for a while because
&lt;code&gt;https://api.gandi.net/v5/domain/domains/annema.me/nameservers&lt;/code&gt; definitely
returned information for annema.me. I &lt;em&gt;had&lt;/em&gt; read in &lt;a href=&quot;https://docs.dnscontrol.org/provider/gandi_v5&quot;&gt;the Gandi provider
documentation&lt;/a&gt; that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is only able to work with domains migrated to the new LiveDNS API&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It wasn&#39;t until I read the
&lt;a href=&quot;https://docs.dnscontrol.org/provider/gandi_v5#debugging&quot;&gt;Debugging&lt;/a&gt; section
that I realized the Gandi provider is calling:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://api.gandi.net/v5/livedns/domains/annema.me/nameservers&quot;&gt;https://api.gandi.net/v5/livedns/domains/annema.me/nameservers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Which, of course, did 404, because, to avoid interruption, my domains are
using Cloudflare instead of Gandi&#39;s LiveDNS.&lt;/p&gt;
&lt;p&gt;Classic. I was trying to automate moving my DNS from Cloudflare to Gandi,
only to end up back at that same text box. However, playing with DNSControl reacquainted me with &lt;a href=&quot;https://en.wikipedia.org/wiki/Zone_file&quot;&gt;DNS zone
files&lt;/a&gt;. I figured that might be what
the text box was silently asking for.&lt;/p&gt;
&lt;h2&gt;The zone file workaround&lt;/h2&gt;
&lt;p&gt;So I could not go from Cloudflare to Gandi, but perhaps I could go from
Cloudflare → DNS zone (BIND) → Gandi. Out of an abundance of caution, I
tested this process with another domain first, and it worked perfectly.&lt;/p&gt;
&lt;p&gt;I updated my dnsconfig.js to include
&lt;code&gt;DnsProvider(DSP_BIND)&lt;/code&gt;. After confirming with &lt;code&gt;dnscontrol preview&lt;/code&gt; that nothing
strange would happen, I ran &lt;code&gt;dnscontrol push&lt;/code&gt; and got a zone file in
&lt;code&gt;./zones/annema.me.zone&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I pasted the zone file content into Gandi&#39;s text box and switched the
nameservers. To verify everything was working, I checked the DNS propagation:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;dig&lt;/span&gt; ns annema.me

&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ANSWER SECTION:
annema.me.              &lt;span class=&quot;token number&quot;&gt;86351&lt;/span&gt;   IN      NS      mona.ns.cloudflare.com.
annema.me.              &lt;span class=&quot;token number&quot;&gt;86351&lt;/span&gt;   IN      NS      yichun.ns.cloudflare.com.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ugh. DNS in a nutshell. &lt;em&gt;Of course&lt;/em&gt; the TTL had just rolled over and would take
almost a full day to propagate.&lt;/p&gt;
&lt;p&gt;But querying Gandi&#39;s nameserver directly confirmed that my records had
migrated successfully:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token function&quot;&gt;dig&lt;/span&gt; @ns-7-a.gandi.net a annema.me&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; ANSWER SECTION:
annema.me.              &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;     IN      A       &lt;span class=&quot;token number&quot;&gt;185.199&lt;/span&gt;.108.153
annema.me.              &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;     IN      A       &lt;span class=&quot;token number&quot;&gt;185.199&lt;/span&gt;.109.153
annema.me.              &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;     IN      A       &lt;span class=&quot;token number&quot;&gt;185.199&lt;/span&gt;.110.153
annema.me.              &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;     IN      A       &lt;span class=&quot;token number&quot;&gt;185.199&lt;/span&gt;.111.153&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Verifying the migration&lt;/h2&gt;
&lt;p&gt;The migration worked perfectly. DNSControl&#39;s zone file export provided
what Gandi&#39;s LiveDNS import expected. What started as a frustrating
manual process became an automated, repeatable solution. Open source and
available on &lt;a href=&quot;https://github.com/klaaspieter/dns&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All that done, my domain names and DNS are now handled by European
companies. Part of my motivation for this move was reducing dependence on
American services given the unpredictability of US politics.&lt;/p&gt;
&lt;p&gt;I have no particular strong feelings about the US, but I do think their
electoral system is problematic. I think it&#39;s an antiquated system invented
to account for horse travel that both parties have kept in place because at
one point or another it favored them. At least that&#39;s the only logical
explanation I can come up with to keep the system in place. Trump is a democratically elected
president under this system, which I believe unfairly gives more power to
less populous states (I know he won the popular vote this time, my point still
stands) and creates exactly the kind of uncertainty that
France&#39;s Europe Minister Benjamin Haddad was referring to:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We cannot leave the security of Europe in the hands of voters in
Wisconsin every four years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The same principle applies to digital infrastructure. By using European providers
I am supporting local infrastructure, reducing dependence on distant
political decisions, and as an EU citizen, having some democratic input
into the regulations that govern my digital rights.&lt;/p&gt;
&lt;p&gt;Next up: moving from GitHub Pages to my Hetzner server.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dynamic bundle identifiers in Xcode: Using xcconfig for different configurations</title>
    <link href="https://annema.me/blog/dynamic-bundle-identifiers-in-xcode-using-xcconfig-for-different-configurations/" />
    <updated>2025-07-17T00:00:00Z</updated>
    <id>https://annema.me/blog/dynamic-bundle-identifiers-in-xcode-using-xcconfig-for-different-configurations/</id>
    <content type="html">&lt;p&gt;Generally in Xcode you have two configurations: Debug and Release. It&#39;s often a good idea to have a different bundle identifier for each configuration so that your debug builds don&#39;t replace the release builds on your device.&lt;/p&gt;
&lt;h2&gt;Normal setup&lt;/h2&gt;
&lt;p&gt;For a single target I usually start with three xcconfig files: &lt;code&gt;Base.xcconfig&lt;/code&gt;, &lt;code&gt;Debug.xcconfig&lt;/code&gt; and &lt;code&gt;Release.xcconfig&lt;/code&gt;. &lt;code&gt;Base.xcconfig&lt;/code&gt; is for build settings shared by both configurations. Versions for each app/extension need to match so that&#39;s a good thing to place in your &lt;code&gt;Base.xcconfig&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Base.xcconfig&lt;/span&gt;
&lt;span class=&quot;token key&quot;&gt;MARKETING_VERSION&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 1.0
&lt;span class=&quot;token key&quot;&gt;CURRENT_PROJECT_VERSION&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Debug.xcconfig&lt;/code&gt; and &lt;code&gt;Release.xcconfig&lt;/code&gt; then look like this:&lt;/p&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Debug.xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;me.annema.app-name.ios.dev&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Release.xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;me.annema.app-name.ios&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See &lt;a href=&quot;https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project/#Map-build-settings-to-a-build-configuration&quot;&gt;Map build settings to a build configuration&lt;/a&gt; for instructions on how to configure your project to use the xcconfig files.&lt;/p&gt;
&lt;h2&gt;Safari extension&lt;/h2&gt;
&lt;p&gt;I&#39;m working on a Safari extension which comes with 4 different targets: iOS app, iOS extension, macOS app and macOS extension. With the above approach that would mean 8 separate xcconfig files that are almost identical. The odds of a typo or copy-paste error are high. I want a single xcconfig file per target that has the &lt;code&gt;dev&lt;/code&gt; suffix for Debug builds and no suffix for Release builds.&lt;/p&gt;
&lt;h2&gt;Conditional values&lt;/h2&gt;
&lt;p&gt;The first obvious thing I tried was to define conditional Debug and Release values:&lt;/p&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Base.xcconfig&lt;/span&gt;
&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER_PREFIX&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me.annema.safari-extension
&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER_SUFFIX&lt;/span&gt;[config&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;Debug] &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; .dev&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// iOS (App).xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX)$(PRODUCT_BUNDLE_IDENTIFIER_SUFFIX)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I expected this to resolve to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debug: &lt;code&gt;me.annema.annema.safari-extension.dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Release: &lt;code&gt;me.annema.safari-extension&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But each configuration resolves to &lt;code&gt;me.annema.safari-extension&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2&gt;The trick&lt;/h2&gt;
&lt;p&gt;It&#39;s then I realized references can be nested:&lt;/p&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Base.xcconfig&lt;/span&gt;
BUNDLE_ID_SUFFIX_Debug &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dev
BUNDLE_ID_SUFFIX_Release &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER_SUFFIX&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(BUNDLE_ID_SUFFIX_$(CONFIGURATION))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Xcode sees the &lt;code&gt;$(CONFIGURATION)&lt;/code&gt; and replaces it with &lt;code&gt;Debug&lt;/code&gt; or &lt;code&gt;Release&lt;/code&gt;. The outer &lt;code&gt;$()&lt;/code&gt; then becomes &lt;code&gt;$(BUNDLE_ID_SUFFIX_Debug)&lt;/code&gt; or &lt;code&gt;$(BUNDLE_ID_SUFFIX_Release)&lt;/code&gt; which Xcode replaces with one of the values we&#39;ve defined on the first two lines: &lt;code&gt;dev&lt;/code&gt; for &lt;code&gt;BUNDLE_ID_SUFFIX_Debug&lt;/code&gt; and nothing for &lt;code&gt;BUNDLE_ID_SUFFIX_Release&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The result&lt;/h2&gt;
&lt;p&gt;To get the final bundle identifier we need to combine the prefix with the suffix and make the value unique for each target. The final &lt;code&gt;Base.xcconfig&lt;/code&gt; therefor defines both a prefix and a suffix:&lt;/p&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Base.xcconfig&lt;/span&gt;
BUNDLE_ID_SUFFIX_Debug &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; .dev
BUNDLE_ID_SUFFIX_Release &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER_PREFIX&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me.annema.safari-extension
&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER_SUFFIX&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(BUNDLE_ID_SUFFIX_$(CONFIGURATION))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The app specific &lt;code&gt;xcconfig&lt;/code&gt;s combine the prefix and suffix:&lt;/p&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// iOS (App).xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX).ios$(PRODUCT_BUNDLE_IDENTIFIER_SUFFIX)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// iOS (Extension).xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX).ios$(PRODUCT_BUNDLE_IDENTIFIER_SUFFIX).web-extension&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// macOS (App).xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX).macos$(PRODUCT_BUNDLE_IDENTIFIER_SUFFIX)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-xcconfig&quot; data-language=&quot;Xcode Configuration&quot;&gt;&lt;code class=&quot;language-xcconfig&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// macOS (Extension).xcconfig&lt;/span&gt;
&lt;span class=&quot;token include&quot;&gt;&lt;span class=&quot;token directive&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Base.xcconfig&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token key&quot;&gt;PRODUCT_BUNDLE_IDENTIFIER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; $(PRODUCT_BUNDLE_IDENTIFIER_PREFIX).macos$(PRODUCT_BUNDLE_IDENTIFIER_SUFFIX).web-extension&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final bundle identifiers resolve to the following. Note that web-extension is a suffix,
this is required because an extension&#39;s bundle identifier needs to be prefixed
by the bundle identifier of the containing app.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Debug&lt;/th&gt;
&lt;th&gt;Release&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;iOS (App)&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.ios.dev&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.ios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iOS (Extension)&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.ios.dev.web-extension&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.ios.web-extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS (App)&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.macos.dev&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.macos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS (Extension)&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.macos.dev.web-extension&lt;/td&gt;
&lt;td&gt;me.annema.safari-extension.macos.web-extension&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content>
  </entry>
  <entry>
    <title>Detecting when an Android permission can only be granted via Settings</title>
    <link href="https://annema.me/blog/detecting-when-an-android-permission-can-only-be-granted-via-settings/" />
    <updated>2025-06-19T00:00:00Z</updated>
    <id>https://annema.me/blog/detecting-when-an-android-permission-can-only-be-granted-via-settings/</id>
    <content type="html">&lt;p&gt;I was surprised to discover how easy it is, even when following the &lt;a href=&quot;https://developer.android.com/training/permissions/requesting&quot;&gt;official Android permissions guide&lt;/a&gt;, to end up with a button that does nothing.&lt;/p&gt;
&lt;h2&gt;Setting the stage: how it works on iOS&lt;/h2&gt;
&lt;p&gt;On iOS &lt;a href=&quot;https://developer.apple.com/documentation/corelocation/clauthorizationstatus&quot;&gt;&lt;code&gt;CLAuthorizationStatus&lt;/code&gt;&lt;/a&gt; has 6 possible states to indicate what level of access a user has granted to their location:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CLAuthorizationStatus&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; notDetermined
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; restricted
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; denied
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; authorized&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CLAuthorizationStatus&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// deprecated&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; authorizedAlways
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; authorizedWhenInUse
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;denied&lt;/code&gt; and &lt;code&gt;notDetermined&lt;/code&gt; cases are crucial because they allow us to differentiate between a user who has been asked for access and rejected it, and a user who has not yet been asked. We know the system shows the permission request UI when &lt;code&gt;CLAuthorizationStatus&lt;/code&gt; is &lt;code&gt;notDetermined&lt;/code&gt;, but does nothing if the status is &lt;code&gt;denied&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As a result, we can create buttons and interfaces that respond appropriately to each state. For example:&lt;/p&gt;
&lt;pre class=&quot;language-plain&quot; data-language=&quot;Plain text&quot;&gt;&lt;code class=&quot;language-plain&quot;&gt;.notDetermined
We need location authorization
[Request authorization]

.denied
We need location authorization
[Open Settings]&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Taking the stage: how it works on Android&lt;/h2&gt;
&lt;p&gt;Consider my surprise when I learned the equivalent Android type is:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot; data-language=&quot;kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; PermissionStatus &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; Granted &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PermissionStatus
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Denied&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; shouldShowRationale&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PermissionStatus
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This type is defined by Google&#39;s &lt;a href=&quot;https://github.com/google/accompanist/blob/fda7f06a24a42b0b1afa75591e768d82d2941984/permissions/src/main/java/com/google/accompanist/permissions/PermissionsUtil.kt#L42-L47&quot;&gt;Accompanist&lt;/a&gt; which builds on top of existing Android APIs for easier access from Jetpack Compose. In truth, Android requires separate APIs to determine whether a permission is granted or denied and if an additional rationale may be shown or not.&lt;/p&gt;
&lt;p&gt;Android does not have an official API for detecting the difference between &lt;code&gt;notDetermined&lt;/code&gt; and &lt;code&gt;denied&lt;/code&gt;. As a result, there’s no standard method to send users to the settings app if they mistakenly reject a permission or want to grant it later. If implemented the official Android way, they will get a button that simply does nothing.&lt;/p&gt;
&lt;p&gt;The maintainer of Accompanist &lt;a href=&quot;https://github.com/google/accompanist/issues/1363#issuecomment-1299910349&quot;&gt;admits&lt;/a&gt; as much and agrees it&#39;s &lt;a href=&quot;https://github.com/google/accompanist/issues/1363#issuecomment-1303072548&quot;&gt;terrible UX&lt;/a&gt;. Luckily someone in the comments provided a &lt;a href=&quot;https://github.com/google/accompanist/issues/1363#issuecomment-1326516265&quot;&gt;partial solution&lt;/a&gt;. It&#39;s partial because it only supports asking for a single permission, but precise location access on Android requires two separate permissions: &lt;code&gt;android.permission.ACCESS_COARSE_LOCATION&lt;/code&gt; and &lt;code&gt;android.permission.ACCESS_FINE_LOCATION&lt;/code&gt;. It works by remembering the original state of the permission and directing the user to Settings if the permission changed from &lt;code&gt;Denied(shouldShowRationale=true)&lt;/code&gt; to &lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Intermission: understanding how permissions change&lt;/h2&gt;
&lt;p&gt;Before we can understand the final solution we need to understand how permissions change as the user rejects all or partial permissions:&lt;/p&gt;
&lt;h3&gt;Rejecting all permissions&lt;/h3&gt;
&lt;p&gt;The flow for rejecting all permissions is the same as for rejecting a single permission, meaning we can use the same approach as the original implementation but looking at all the requested permissions instead.&lt;/p&gt;
&lt;h4&gt;Initial state&lt;/h4&gt;
&lt;p&gt;The state of permissions when the user first launches the app or has previously rejected all permissions.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;PermissionStatus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;First rejection&lt;/h4&gt;
&lt;p&gt;After the user first rejects permissions Android gives us the opportunity to provide an additional rationale for why it&#39;s necessary:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;PermissionStatus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=true)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=true)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Second rejection&lt;/h4&gt;
&lt;p&gt;Because the user rejects the permission again we&#39;re no longer allowed to show a rationale. The system will no longer show system UI when asked.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;PermissionStatus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;The important state change&lt;/h4&gt;
&lt;p&gt;Because the permission state changes from &lt;code&gt;Denied(shouldShowRationale=true)&lt;/code&gt; to &lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;, we know that the user has denied us for the final time and can instead open the Settings app.&lt;/p&gt;
&lt;p&gt;In code:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot; data-language=&quot;kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;currentState &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Denied &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; currentState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
newState &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Denied &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;newState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Rejecting partial permissions&lt;/h2&gt;
&lt;p&gt;The flow for partial permissions is slightly different:&lt;/p&gt;
&lt;h4&gt;Initial state&lt;/h4&gt;
&lt;p&gt;The state of permissions when the user first launches the app or has previously rejected all permissions.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;PermissionStatus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Partial approval&lt;/h4&gt;
&lt;p&gt;The user allowed coarse location, but not fine.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;PermissionStatus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Granted&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Second partial approval&lt;/h4&gt;
&lt;p&gt;The user is asked to change location access from coarse to fine but rejects it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Permission&lt;/th&gt;
&lt;th&gt;PermissionStatus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_COARSE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Granted&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACCESS_FINE_LOCATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Denied(shouldShowRationale=false)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;The important state change&lt;/h4&gt;
&lt;p&gt;In this case we see that with the first and second partial approvals the permission state doesn&#39;t change at all. We can detect this specific state by making sure that at least one permission was granted and the permission state didn&#39;t change:&lt;/p&gt;
&lt;pre class=&quot;language-kotlin&quot; data-language=&quot;kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newPermissionStates&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isGranted &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; currentPermissionsStates &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; newPermissionStates&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, there is still an issue with this approach. After rejecting the change from approximate to precise location, the system UI dismisses and the Settings app opens immediately. Ideally this would happen the next time they tap the button, like it does when all permissions are rejected. I decided that this is good enough for me. It should be relatively rare and I&#39;ve already spend more time on this than I wanted.&lt;/p&gt;
&lt;h2&gt;Applause: the full solution&lt;/h2&gt;
&lt;pre class=&quot;language-kotlin&quot; data-language=&quot;kotlin&quot;&gt;&lt;code class=&quot;language-kotlin&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; io&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ipinfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extensions

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Activity
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContextWrapper
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PackageManager
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; android&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Log
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Composable
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Stable
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;derivedStateOf
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getValue
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mutableStateOf
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;remember
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runtime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setValue
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;compose&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ui&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LocalContext
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ActivityCompat
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; androidx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;core&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContextCompat
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ExperimentalPermissionsApi
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MultiplePermissionsState
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PermissionState
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PermissionStatus
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isGranted
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rememberMultiplePermissionsState
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rememberPermissionState
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;google&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accompanist&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale

&lt;span class=&quot;token comment&quot;&gt;// Extend Accompanist to detect when a permission needs to be granted through the Settings app.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Inspired by: https://github.com/google/accompanist/issues/1363#issuecomment-1326516265&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/** Find the closest Activity in a given Context. */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Activity &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; ContextWrapper&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; Activity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; context
        context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;baseContext
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IllegalStateException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Permissions should be called in the context of an Activity&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ContextCompat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkSelfPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;
        PackageManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PERMISSION_GRANTED
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; Activity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldShowRationale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ActivityCompat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldShowRequestPermissionRationale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; TAG &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal singleline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ExtendedAccompanist&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/** `true` if a rationale should be presented to the user. */&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@ExperimentalPermissionsApi&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean
    &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Granted &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Denied &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; shouldShowRationale
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@ExperimentalPermissionsApi&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rememberPermissionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        permission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onCannotRequestPermission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onPermissionResult&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExtendedPermissionState &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LocalContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current

    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; currentShouldShowRationale &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; remember &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldShowRationale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; atDoubleDenialForPermission &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; remember &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; mutablePermissionState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;rememberPermissionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; isGranted &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isGranted&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; updatedShouldShowRationale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                            context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldShowRationale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;currentShouldShowRationale &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;updatedShouldShowRationale&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                            &lt;span class=&quot;token function&quot;&gt;onCannotRequestPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;currentShouldShowRationale &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;updatedShouldShowRationale&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                            atDoubleDenialForPermission &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;onPermissionResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isGranted&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;remember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ExtendedPermissionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                permission &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; permission&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                mutablePermissionState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                onCannotRequestPermission &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onCannotRequestPermission&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                atDoubleDenial &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; atDoubleDenialForPermission&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                onLaunchedPermissionRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; currentShouldShowRationale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; it &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalPermissionsApi&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;permissionStates&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; permissions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Map&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PermissionStatus&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;associate&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            it &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Granted
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            it &lt;span class=&quot;token keyword&quot;&gt;to&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Denied&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                shouldShowRationale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldShowRationale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalPermissionsApi&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@Composable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rememberMultiplePermissionsState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        permissions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onPermissionsResult&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Map&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Boolean&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        onCannotRequestPermission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExtendedMultiplePermissionState &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LocalContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; currentPermissionsStates &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; remember &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;permissionStates&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; permissions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; atDoubleDenialForPermission &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; remember &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mutableStateOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; mutablePermissionState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;rememberMultiplePermissionsState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    permissions&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    onPermissionsResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; newPermissions &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; newPermissionStates &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newPermissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mapValues&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                                PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Granted
                            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                                PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Denied&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                                    shouldShowRationale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findActivity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shouldShowRationale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

                        Log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                            TAG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;token string-literal multiline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&quot;
                               ------------
                               onPermissionResult
                               current: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;currentPermissionsStates&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
                               new: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;newPermissionStates&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
                               --------------
                            &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trimIndent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

                        &lt;span class=&quot;token comment&quot;&gt;// show settings when at least one permission is denied and the current and new permissions haven&#39;t changed.&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newPermissionStates&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isGranted &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; currentPermissionsStates &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; newPermissionStates&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;token function&quot;&gt;onCannotRequestPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permission &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; permissions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                                &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; currentState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentPermissionsStates&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                                &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; newState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newPermissionStates&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                                    currentState &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Denied &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; currentState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                                    newState &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Denied &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;newState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale
                                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                                    &lt;span class=&quot;token function&quot;&gt;onCannotRequestPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;
                                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

                        &lt;span class=&quot;token function&quot;&gt;onPermissionsResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newPermissions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;remember&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ExtendedMultiplePermissionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                permissions &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                mutablePermissionState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                onCannotRequestPermission &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; onCannotRequestPermission&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                atDoubleDenial &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; atDoubleDenialForPermission&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                onLaunchedPermissionRequest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    currentPermissionsStates &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;permissionStates&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; permissions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

                    Log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                        TAG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;token string-literal multiline&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&quot;
                            onLaunchedPermissionRequest
                            current: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;currentPermissionsStates&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
                        &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trimIndent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalPermissionsApi&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@Stable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ExtendedPermissionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; permission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PermissionState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; atDoubleDenial&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onLaunchedPermissionRequest&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shouldShowRationale&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onCannotRequestPermission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PermissionState &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PermissionStatus
        &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status

    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;launchPermissionRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;onLaunchedPermissionRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;atDoubleDenial&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onCannotRequestPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;launchPermissionRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation builtin&quot;&gt;@OptIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExperimentalPermissionsApi&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation builtin&quot;&gt;@Stable&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ExtendedMultiplePermissionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; permissions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;PermissionState&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MultiplePermissionsState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; atDoubleDenial&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onLaunchedPermissionRequest&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shouldShowRationale&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; onCannotRequestPermission&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; Unit
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MultiplePermissionsState &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; revokedPermissions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; List&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;PermissionState&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; derivedStateOf &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; PermissionStatus&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Granted &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; allPermissionsGranted&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; derivedStateOf &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isGranted &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Up to date when the lifecycle is resumed&lt;/span&gt;
        revokedPermissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Up to date when the user launches the action&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; shouldShowRationale&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Boolean &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; derivedStateOf &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                permissions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;none&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isGranted &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;launchMultiplePermissionRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;onLaunchedPermissionRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shouldShowRationale&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;atDoubleDenial&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onCannotRequestPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; mutablePermissionState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;launchMultiplePermissionRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>New website</title>
    <link href="https://annema.me/blog/new-website/" />
    <updated>2025-06-09T00:00:00Z</updated>
    <id>https://annema.me/blog/new-website/</id>
    <content type="html">&lt;p&gt;I wrote my &lt;a href=&quot;https://annema.me/blog/archive/2016-05-05-find-time-zones-where-its-currently-a-certain-time/&quot;&gt;last blog post in 2016&lt;/a&gt;. Ever since I felt like I wasn&#39;t doing anything worth writing about. I was no longer enjoying myself as a software developer. I burned out. There were a lot of factors that contributed to my burnout but one of them was definitely that I no longer enjoyed the way I built software. Unfortunately it took years to gain the insight that I still enjoyed making products, but not the way I was making them.&lt;/p&gt;
&lt;p&gt;There were many ideas and inspirations that contributed to my recovery. On a personal level raising my kids taught me valuable lessons in
recognizing, feeling and dealing with my own emotions. Through &lt;a href=&quot;https://podcasts.apple.com/us/podcast/the-raising-humans-kind-podcast/id1607415212&quot;&gt;the raising humans kind
podcast&lt;/a&gt;, &lt;a href=&quot;https://bookshop.org/p/books/the-explosive-child-sixth-edition-a-new-approach-for-understanding-and-parenting-easily-frustrated-chronically-inflexible-children-ross-w-greene/16504899?ean=9780063092471&amp;amp;digital=t&quot;&gt;The explosive child&lt;/a&gt; and &lt;a href=&quot;https://bookshop.org/p/books/how-to-talk-so-kids-will-listen-listen-so-kids-will-talk-adele-faber/12161462?ean=9781451663884&amp;amp;next=t&quot;&gt;How to talk so kids will listen &amp;amp; listen so kids will talk&lt;/a&gt; I discovered a different way to raise my kids while simultaneously learning how to better recognize my own emotions. It&#39;s hard to summarize but if I had to it&#39;s: Respect feelings; limit behavior. It&#39;s okay to be sad; it&#39;s not okay to hit your siblings.&lt;/p&gt;
&lt;p&gt;As a way to remind ourselves that all feelings are okay we have this Inside out poster
framed on a wall in our living room:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://annema.me/images/feel-what-you-need-to-feel.jpg&quot; alt=&quot;An inside out inspired poster we hung in our living room. It shows the 5 main characters of Inside out with text below it. The text reads: Our emotions are meant to be felt. Even the hard ones. It&#39;s okay to feel what you need to feel.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Professionally I learned about the term &lt;a href=&quot;https://posthog.com/careers/product-engineer&quot;&gt;Product developer from PostHog&lt;/a&gt; which gave name to my professional identity. I&#39;ve always known I&#39;m not a typical software developer but it wasn&#39;t until I learned of the concept product developer that I was able to truly understand and articulate the difference.&lt;/p&gt;
&lt;p&gt;I skipped a lot of things that contributed to my burnout; heck I probably
haven&#39;t discovered a lot of the reasons. All the insights I did gain brought me
to a simple conclusion: I lost the joy of creation.&lt;/p&gt;
&lt;p&gt;Recovering from burnout was finding that joy again and I did.&lt;/p&gt;
&lt;p&gt;I found it in &lt;a href=&quot;https://annema.me/health-shortcuts&quot;&gt;Health shortcuts&lt;/a&gt; and &lt;a href=&quot;https://annema.me/brb&quot;&gt;brb&lt;/a&gt;. I started
building iOS apps in 2007 (yes, before there was an official SDK) but these are
the first apps I published myself. I&#39;m incredible proud of my apps but
simultaneously I tire of their uniformity. iOS and Android are optimized to
make apps that look and feel like any other app. While it means someone with little
visual design talent, me, can ship something by myself, it also means
every app looks and feels the same. I scratched my creative
itch, but I was still itching.&lt;/p&gt;
&lt;p&gt;It&#39;s then I found a new community. A community that has existed since the early days of the internet. A community that has persisted through the uniformity of &lt;a href=&quot;https://getbootstrap.com&quot;&gt;Bootstrap&lt;/a&gt; and &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind&lt;/a&gt;. A community &lt;a href=&quot;https://infrequently.org/2024/11/if-not-react-then-what/&quot;&gt;that articulated some of my feelings about React&lt;/a&gt;. A community that exists outside of walled gardens. A community that is accessible to anyone (with a computer and an internet connection). A community that believes in owning our part of the internet.&lt;/p&gt;
&lt;p&gt;I started following &lt;a href=&quot;https://piccalil.li/&quot;&gt;Piccalily&lt;/a&gt; and &lt;a href=&quot;https://bell.bz/&quot;&gt;Andy Bell&lt;/a&gt;. I began learning about &lt;a href=&quot;https://moderncss.dev/&quot;&gt;Modern CSS&lt;/a&gt;. I noticed the &lt;a href=&quot;https://mastodon.design/@kp/113973549654064551&quot;&gt;similarities between mobile and web development&lt;/a&gt;, &lt;a href=&quot;https://mastodon.design/@kp/113973569959490378&quot;&gt;accepted that modern software development is different than when I started&lt;/a&gt; and realized the web has always been better at non-uniform responsive and inclusive design than even SwiftUI and Jetpack Compose are today.&lt;/p&gt;
&lt;p&gt;Most importantly I found myself using view source to see how &lt;a href=&quot;https://lea.verou.me/blog/&quot;&gt;Lea
Verou&lt;/a&gt; made the sun in the blog header animate. To
&lt;a href=&quot;https://nordhealth.design/&quot;&gt;get inspiration for naming my variables&lt;/a&gt;. To learn
how &lt;a href=&quot;https://www.alwaystwisted.com/about/&quot;&gt;Stuart&lt;/a&gt; made his customizable
background pattern work. Dreamed about one day having a site so cool that it&#39;s
&lt;a href=&quot;https://alistairshepherd.uk/&quot;&gt;vibe changes based on the time off
day&lt;/a&gt;. I appreciated all this for what it was: &lt;a href=&quot;https://mastodon.design/@kp/114042674835768877&quot;&gt;art&lt;/a&gt;. Accessible to anyone.&lt;/p&gt;
&lt;p&gt;I left all the walled gardens but I didn&#39;t replace it with anything. This &lt;em&gt;gestures to the surroundings&lt;/em&gt; is my replacement. My own humble space on the internet. Outside of any walled gardens and accessible to anyone. Welcome.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Find time zones where it&#39;s currently a certain time</title>
    <link href="https://annema.me/blog/archive/2016-05-05-find-time-zones-where-its-currently-a-certain-time/" />
    <updated>2016-05-05T08:18:00Z</updated>
    <id>https://annema.me/blog/archive/2016-05-05-find-time-zones-where-its-currently-a-certain-time/</id>
    <content type="html">&lt;p&gt;For a project I&#39;m working I needed a function that returns the time zones where it&#39;s currently 9am. I generalized the function to be able to find time zones where it&#39;s currently any time. My Swift implementation was inspired by this &lt;a href=&quot;http://stackoverflow.com/a/36284082/1555903&quot;&gt;stackoverflow answer&lt;/a&gt;, providing code for the same problem in Ruby.&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;timeZonesWhereItIs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hour&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token omit keyword&quot;&gt;_&lt;/span&gt; minute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NSTimeZone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; calendar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;calendarIdentifier&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSCalendarIdentifierGregorian&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  calendar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timeZone &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSTimeZone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;UTC&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; currentUTCTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSTimeZone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;knownTimeZoneNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;flatMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NSTimeZone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filter &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; timeZone &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; components &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; calendar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;componentsInTimeZone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeZone&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fromDate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      components&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hour &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; hour
      components&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;minute &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; minute
      &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; calendar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dateFromComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;components&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;

      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; calendar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;date&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; equalToDate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; currentUTCTime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; toUnitGranularity&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Hour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;timeZonesWhereItIs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To find a time zone at each hour offset use it as follows:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;timesZonesForEveryHour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NSTimeZone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flatMap &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;timeZonesWhereItIs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;first &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that there are time zones that are offset by &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_UTC_time_offsets&quot;&gt;30 and 15 minutes&lt;/a&gt;. This function won&#39;t return those.&lt;/p&gt;
&lt;p&gt;Have fun.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Gesture Recognizers in Swift</title>
    <link href="https://annema.me/blog/archive/2015-07-09-gesture-recognizers-in-swift/" />
    <updated>2015-07-08T22:52:00Z</updated>
    <id>https://annema.me/blog/archive/2015-07-09-gesture-recognizers-in-swift/</id>
    <content type="html">&lt;p&gt;I wrote about using &lt;a href=&quot;https://thatthinginswift.com/gesture-recognizers-swift/&quot;&gt;Gesture Recognizers in Swift&lt;/a&gt; for &lt;a href=&quot;https://thatthinginswift.com&quot;&gt;thatthinginswift.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I ran into a couple of surprises using gesture recognizers in Swift. Nothing major, but definitely things to look out for. Head over to &lt;a href=&quot;https://thatthinginswift.com/gesture-recognizers-swift&quot;&gt;the article&lt;/a&gt; to read more about it.&lt;/p&gt;
&lt;p&gt;Nick is also looking for more contributors. If you&#39;re interested send a &lt;a href=&quot;https://github.com/nickoneill/thatthinginswift/pulls&quot;&gt;PR&lt;/a&gt;. If you need inspiration for topics take a look at issues &lt;a href=&quot;https://github.com/nickoneill/thatthinginswift/issues/8&quot;&gt;8&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Ruby&#39;s tap method in Swift</title>
    <link href="https://annema.me/blog/archive/2015-03-18-rubys-tap-method-in-swift/" />
    <updated>2015-03-18T12:38:00Z</updated>
    <id>https://annema.me/blog/archive/2015-03-18-rubys-tap-method-in-swift/</id>
    <content type="html">&lt;p&gt;Ruby has a nice method called &lt;code&gt;tap&lt;/code&gt;, which I wanted to try and port to Swift. To learn what it does, let&#39;s take a look at &lt;a href=&quot;http://ruby-doc.org/core-2.2.0/Object.html#method-i-tap&quot;&gt;Ruby&#39;s documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yields self to the block, and then returns self. The primary purpose of this method is to &amp;quot;tap into&amp;quot; a method chain, in order to perform operations on intermediate results within the chain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, right. I don&#39;t really know what that means. Googling yields (no pun intended) many contrived examples like these:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot; data-language=&quot;ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tap &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:reverse!&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# [4, 3, 2, 1]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Swift the same can be written as:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reverse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [4, 3, 2, 1]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A less contrived example would be:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot; data-language=&quot;ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tap &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
    user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Yukihiro Matsumoto&quot;&lt;/span&gt;&lt;/span&gt;
    user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;known_for &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ruby&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the latter case tap is acting as a sort of &lt;a href=&quot;http://www.annema.me/the-builder-pattern-in-swift&quot;&gt;improptu builder&lt;/a&gt;. In Swift:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Chris Lattner&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;knownFor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Swift&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the previous example requires every property of the user to be mutable (&lt;code&gt;var&lt;/code&gt;). This example should only be seen as a comparison to Ruby. Please don&#39;t do this in your actual code unless you absolutely have to.&lt;/p&gt;
&lt;p&gt;That said, we&#39;ve established a public API, it&#39;s time to start implementing. If you want to follow along; I&#39;ve made a &lt;a href=&quot;https://gist.github.com/klaaspieter/9d8ce4485007fcb973b7&quot;&gt;playground available&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the Ruby source &lt;a href=&quot;https://github.com/ruby/ruby/blob/e28c3d5df4f5abc83e0d2de34e7ebf675c96a307/object.c#L684-L689&quot;&gt;tap&lt;/a&gt; is implemented like so:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; data-language=&quot;c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;VALUE
&lt;span class=&quot;token function&quot;&gt;rb_obj_tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;VALUE obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;rb_yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Translating that to actual Ruby:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot; data-language=&quot;ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Object&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token method-definition&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My first attempt was a copy of Ruby&#39;s implementation, but in a global function. I&#39;m not a huge fan of the global functions in Swift, but it works out nicely because we won&#39;t have to extend any existing objects.&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnyObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;AnyObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AnyObject&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; object
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great, we threw out all type safety in an attempt to be as dynamic as Ruby. It also doesn&#39;t compile.&lt;/p&gt;
&lt;p&gt;Let&#39;s introduce some generics:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;inout&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;object&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; object
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does compile, and it&#39;s type safe to boot:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reverseInPlace&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that Swift doesn&#39;t have a built-in reverse in place method like Ruby does. If you&#39;re interested in what that looks like; take a look at &lt;a href=&quot;https://gist.github.com/klaaspieter/9d8ce4485007fcb973b7&quot;&gt;the gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A less contrived example would be:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NSDateComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;day &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;
    &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;month &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;06&lt;/span&gt;
    &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1986&lt;/span&gt;
    &lt;span class=&quot;token short-argument&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;calendar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;currentCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you got this far, you might be wondering: do we need a &lt;code&gt;tap&lt;/code&gt; function? The answer is: maybe. In Objective-C we could use &lt;a href=&quot;http://www.annema.me/builder-and-gcc-code-block-evaluation&quot;&gt;GCC code block evaluation&lt;/a&gt; to similar effect. In Swift we should be able to write:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSDateComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;day &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;month &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;06&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1986&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;calendar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;currentCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; c
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately this confuses the type system. It is unable to infer the return type of the block. Instead we have to write:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSDateComponents&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSDateComponents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;day &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;month &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;06&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1986&lt;/span&gt;
    c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;calendar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NSCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;currentCalendar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; c
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;date&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For now, &lt;code&gt;tap&lt;/code&gt; is a safer and arguably more readable alternative but it&#39;s likely that the Swift compiler will solve the entire issue more elegantly in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Several people on Twitter have pointed out to me that my implementation wasn&#39;t an exact reproduction. The post has been updated with a better implementation. If you&#39;re interested in my incorrect implementations take a look at the revision history of &lt;a href=&quot;https://gist.github.com/klaaspieter/9d8ce4485007fcb973b7/revisions&quot;&gt;the gist&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Builder Pattern in Swift</title>
    <link href="https://annema.me/blog/archive/2015-02-02-the-builder-pattern-in-swift/" />
    <updated>2015-02-02T19:51:00Z</updated>
    <id>https://annema.me/blog/archive/2015-02-02-the-builder-pattern-in-swift/</id>
    <content type="html">&lt;p&gt;A while ago I wrote a post about implementing the builder pattern in Objective-C. Today we&#39;re going to do the same for Swift.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;http://www.annema.me/the-builder-pattern-in-objective-c&quot;&gt;previous post&lt;/a&gt; the end result was:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pizza &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Pizza pizzaWithBlock&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PizzaBuilder &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a couple of things that can be improved here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The syntax.
I don&#39;t mind Objective-C, but there are definitely some superfluous characters.&lt;/li&gt;
&lt;li&gt;Failability.
A pizza without a size doesn&#39;t make sense. Adding this to Objective-C is not impossible, but a decision has to be made on how to represent failures. Do we throw an exception when a size isn&#39;t set? Return nil from an initializer? Maybe even have an isValid method with an error parameters that is returned by reference?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In turns out, builder can be done better in Swift. This is what it looks like when using the same &lt;code&gt;Pizza&lt;/code&gt; example from the previous post:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Pizza&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; builder &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cheese &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Mozzarella&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Pizza&lt;/code&gt; initializer takes a block, with the builder as it&#39;s parameter. In the &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html&quot;&gt;trailing closure&lt;/a&gt; we set the properties of the pizza. So far it&#39;s exactly the same as Objective-C with slightly better syntax. From this point on things are different. After the block is executed we have an &lt;em&gt;optional&lt;/em&gt; Pizza, whereas in Objective-C we had a potentially invalid Pizza. As mentioned before, preventing this in Objective-C is possible, but a decision has to be made on how to present the error. In my experience these kinds of errors usually end up being ignored, becoming a hard to find bug at some point in the future.&lt;/p&gt;
&lt;p&gt;Back to Swift; we ended with an optional Pizza. By making the result an optional we make it easier to deal with physical impossibilities; like a Pizza without a size. To see how this works, take a look at the initializers:&lt;/p&gt;
&lt;pre class=&quot;language-swift&quot; data-language=&quot;swift&quot;&gt;&lt;code class=&quot;language-swift&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;PizzaBuilder&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; builder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PizzaBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PizzaBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cheese &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cheese
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni
        &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token nil constant&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both initializers are what are called &lt;a href=&quot;https://developer.apple.com/swift/blog/?id=17&quot;&gt;failable initializers&lt;/a&gt;. They either return an optional Pizza or nil. In our example the only way the initializer fails is when the size isn&#39;t 12, 14, or 16 inch.&lt;/p&gt;
&lt;p&gt;Check out my entire &lt;code&gt;Pizza&lt;/code&gt; implementation in &lt;a href=&quot;https://gist.github.com/klaaspieter/c05e843896abfa70f5cb&quot;&gt;this gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Swift arguably makes the syntax for a builder nicer. It also makes modeling failure easier by making it a core part of the language. After the Pizza is initialized from the builder there is only one question left: Is the Pizza a lie?&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Configure your iOS app for multiple environments</title>
    <link href="https://annema.me/blog/archive/2014-11-20-configure-your-ios-app-for-multiple-environments/" />
    <updated>2014-11-20T18:50:00Z</updated>
    <id>https://annema.me/blog/archive/2014-11-20-configure-your-ios-app-for-multiple-environments/</id>
    <content type="html">&lt;p&gt;Two weeks ago I wrote a post about &lt;a href=&quot;http://www.annema.me/clean-up-the-application-delegate-with-initializers&quot;&gt;cleaning up your application delegate with initializers&lt;/a&gt;. I eluded to a &lt;code&gt;Configuration&lt;/code&gt; object in that post. I decided to make this two separate posts because they&#39;re different concepts that happen to work together.&lt;/p&gt;
&lt;p&gt;The Karma app has to run in 3 environments: Development, Pre-release and Production. We also have some secondary environments, like Test and Device, which are subsets of respectively Development and Production.&lt;/p&gt;
&lt;p&gt;Each environment is different. In Development crashes are not reported and Facebook&#39;s development environment is used for authentication. In production (read: App Store) crashes are reported and the app communicates with our production APIs. This requires connecting to different URLs and authenticating with different keys.&lt;/p&gt;
&lt;p&gt;One solution, unfortunately used frequently, is preprocessor macros. When you create a project, Xcode &lt;a href=&quot;https://developer.apple.com/library/mac/technotes/tn2347/_index.html#//apple_ref/doc/uid/DTS40014516-CH1-THE_DEBUG_PREPROCESSOR_MACRO&quot;&gt;automatically configures&lt;/a&gt; a &lt;code&gt;DEBUG=1&lt;/code&gt; preprocessor macro for Debug builds. The macro is not defined for release builds so it&#39;s possible to target different environments:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;DEBUG&lt;/span&gt;&lt;/span&gt;
NSString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; KPAThirdPartyServiceKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;debug123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
NSString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; KPAThirdPartyServiceKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;release123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is known as &lt;a href=&quot;http://en.wikipedia.org/wiki/C_preprocessor#Conditional_compilation&quot;&gt;conditional compilation&lt;/a&gt;. The code in the &lt;code&gt;DEBUG&lt;/code&gt; block will not be part of a Release build and vice versa. Meaning both environments run different code. This is great if you&#39;re targeting different architectures, say ARM and Intel, because doing the same thing requires different APIs.&lt;/p&gt;
&lt;p&gt;It&#39;s awful for configuring environment, because 1) it&#39;s an unnecessary conditional (that doesn&#39;t indent in Xcode) 2) you&#39;re literally shipping code that&#39;s different from what you use to debug. In this simple example it will likely never cause problems, but it&#39;ll become more complicated over time. Consider what happens when introducing a third environment. As mentioned before, the Karma app has 3 primary environments and several subsets of those. Using conditional compilations, we would need several levels of nested conditionals to support every environment.&lt;/p&gt;
&lt;p&gt;What we want is a way to automatically load different configurations for different environments. We&#39;ll need 3 things to make this work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An object to hold the configuration values&lt;/li&gt;
&lt;li&gt;A way of differentiating between environments (without using conditional compilation and preferably no other type of conditional)&lt;/li&gt;
&lt;li&gt;A system to load different configuration values for each environment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;ve made an &lt;a href=&quot;https://github.com/klaaspieter/configuration&quot;&gt;example project&lt;/a&gt; available on Github that has these 3 things. Let&#39;s go over them one by one.&lt;/p&gt;
&lt;h2&gt;The Configuration Object&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/klaaspieter/configuration/blob/master/Configuration/Configuration.m&quot;&gt;&lt;code&gt;Configuration&lt;/code&gt;&lt;/a&gt; object solves requirement one. It holds configuration values in a dictionary and makes them available through a &lt;code&gt;settingForKey:&lt;/code&gt; method. The object also partially solves requirement 3 because it can populate itself by loading a plist. More on that later.&lt;/p&gt;
&lt;h2&gt;Differentiating between environments&lt;/h2&gt;
&lt;p&gt;Before we can fully solve requirement 3 we first need a way of differentiating between environments. I&#39;ve done this in the example project by creating different build configurations. In Xcode 6.1 you can find build configurations by clicking on the project in the Project Navigator then selecting the project again under &amp;quot;PROJECT&amp;quot; in the editor. From there go to the &amp;quot;Info&amp;quot; tab. You should see a &amp;quot;Configurations&amp;quot; section, which by default, has a Debug and Release configuration. In the example project I called them: Development, Staging and Production. You can create as many as needed and give them any name you see fit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/ceNaKmy.gif&quot; alt=&quot;Changing build configurations gif&quot;&gt;&lt;/p&gt;
&lt;p&gt;For convenience I also created a scheme for each build configuration. This makes it easy to build for a certain environment by simply selecting it&#39;s corresponding scheme.&lt;/p&gt;
&lt;h2&gt;Loading different configurations per environment&lt;/h2&gt;
&lt;p&gt;Now that we have a way to differentiate between environments it&#39;s time to discover how we can load a configuration for each. This is already partially solved by the &lt;code&gt;Configuration&lt;/code&gt; object. In the &lt;code&gt;loadDefaults&lt;/code&gt; method it will search for the &lt;code&gt;ConfigurationPlist&lt;/code&gt; key in the Info.plist. In other words: all we need is a way to make this key have a different value for each environment.&lt;/p&gt;
&lt;p&gt;When a value in the Info.plist is enclosed in $(), the key between () will be looked up in your build settings (I searched for documentation on this, but couldn&#39;t find any). In the example project the &lt;code&gt;ConfigurationPlist&lt;/code&gt; value is $(CONFIGURATION_PLIST). To make it work, we need to add a build setting called &amp;quot;CONFIGURATION_PLIST&amp;quot; and give it a different value for each build configuration.&lt;/p&gt;
&lt;p&gt;To add a build setting, select the project in the Project Navigator, select the target (in the Example app it&#39;s called &amp;quot;Configuration&amp;quot;) under &amp;quot;PROJECTS&amp;quot; and switch to the &amp;quot;Build Settings&amp;quot; tab. In this tab you can add more build settings by clicking the plus icon and selecting &amp;quot;Add User-Defined Setting&amp;quot; from the popup menu. Name it &amp;quot;CONFIGURATION_PLIST&amp;quot;. Now click the arrow on the left side, you&#39;ll see that Xcode allows you to change the value for each build configuration. How you name these is up to you. I follow [Environment]-Config as a naming pattern.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://i.imgur.com/BFwGPbG.gif&quot; alt=&quot;Adding custom build settings gif&quot;&gt;&lt;/p&gt;
&lt;p&gt;The final step is to create the plists. If you look at the example project you&#39;ll see there is one plist for each environment: Development-Config.plist, Staging-Config.plist and Production-Config.plist. I also added two keys: &lt;code&gt;environment&lt;/code&gt; and &lt;code&gt;report_crashes&lt;/code&gt;. These are just two examples, you can add any configuration options in these plists.&lt;/p&gt;
&lt;p&gt;All that&#39;s left is to access your settings at runtime:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Configuration defaultConfiguration&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; settingForKey&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;report_crashes&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;In the Karma app I combine this approach with the &lt;a href=&quot;http://www.annema.me/clean-up-the-application-delegate-with-initializers&quot;&gt;Initializer pattern&lt;/a&gt; I explained in my previous blog post. Each initializer is passed a Configuration object, allowing it to grab the settings it needs to initialize the portion of the app it&#39;s responsible for.&lt;/p&gt;
&lt;p&gt;It takes some setup, but you end up with an easy way of loading distinct settings per environment. Adding more environments takes a couple of steps, but it&#39;s a lot easier than having to go through your code and update conditionals and hardcoded strings everywhere.&lt;/p&gt;
&lt;p&gt;While writing this post I discovered &lt;a href=&quot;https://github.com/krzysztofzablocki/KZBootstrap#environments&quot;&gt;KZBootstrap&lt;/a&gt; attempts to solve the same problem. I haven&#39;t looked at it in detail, but being able to change configurations at runtime is one thing it has over my solution. When it comes to using it I have to agree with Dave Verwer who had this to say about it in &lt;a href=&quot;http://iosdevweekly.com/issues/168&quot;&gt;issue 168&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, before you jump in with both feet I&#39;m not completely convinced that iOS projects actually need a bootstrap. There are some good recommendations here though so what I would recommend is to take a look at this, spend some time understanding it and then pick bits that work for you. Blindly using someone else&#39;s defaults is only going to lead to surprises down the line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;ve thought about open sourcing my approach, but haven&#39;t figured out how to automate the Xcode setup. There is promise in &lt;a href=&quot;https://github.com/CocoaPods/cocoapods-plugins&quot;&gt;some&lt;/a&gt; of the &lt;a href=&quot;https://github.com/CocoaPods/Xcodeproj&quot;&gt;tools&lt;/a&gt; that power CocoaPods, but haven&#39;t had the time yet to look into it.&lt;/p&gt;
&lt;p&gt;I&#39;m happy to see that more developer are trying to solve this problem. From my experience it&#39;s something most of us run into at some point. When I wrote my solution I couldn&#39;t find anyone who&#39;d shared their solution, forcing me to come up with my own.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Clean up the application delegate with initializers</title>
    <link href="https://annema.me/blog/archive/2014-10-30-clean-up-the-application-delegate-with-initializers/" />
    <updated>2014-10-30T16:48:00Z</updated>
    <id>https://annema.me/blog/archive/2014-10-30-clean-up-the-application-delegate-with-initializers/</id>
    <content type="html">&lt;p&gt;The application delegate has a tendency to become unwieldy. It provides a ton of callbacks to respond to about every possible state change of your app. The method that grows quickest is usually &lt;code&gt;applicationDidFinishLaunching:withOptions:&lt;/code&gt;&lt;sup&gt;[citation needed]&lt;/sup&gt;. From preloading content for a better experience, to configuration third party services, it all tends to end up in that same method.&lt;/p&gt;
&lt;p&gt;I&#39;ve been using the concepts of initializers recently. An initializer is an object that conforms to the &lt;code&gt;Initializer&lt;/code&gt; protocol with just one required method: &lt;code&gt;performWithConfiguration:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You might wonder what the configuration argument is, but for now I want to focus on the concept of initializers. For the purpose of this blog post it is sufficient to think of the configuration object as a dictionary that contains configuration options. For example: keys for third party services, or the log level.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at an initializer implementation. This is the initializer I use to configure HockeyApp in the &lt;a href=&quot;https://itunes.apple.com/us/app/karma-wifi/id673069729?ls=1&amp;amp;mt=8&quot;&gt;Karma app&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;performWithConfiguration&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Configuration&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;configuration&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;configuration settingForKey&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;HockeyAppIdentifierKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;DDLogWarn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;No Hockey Identifier in configuration: %@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; configuration&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    BITHockeyManager &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;manager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BITHockeyManager sharedHockeyManager&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    id delegate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;UIApplication sharedApplication&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;delegate&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;manager configureWithIdentifier&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;configuration settingForKey&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;HockeyAppIdentifierKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; delegate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;delegate&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;disableCrashManager &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;configuration settingForKey&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;HockeyAppCrashesDisabledKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; boolValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;crashManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;crashManagerStatus &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BITCrashManagerStatusAutoSend&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;manager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authenticator authenticateInstallation&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;manager startManager&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Initializers aren&#39;t always about third party services. The following initializer preloads the store whenever the app launches. Notice that it completely ignores the configuration argument:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;@implementation&lt;/span&gt; StoreInitializer

&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;performWithConfiguration&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Configuration&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;configuration&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ProductFetcher sharedFetcher&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; fetch&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BOOL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;shouldPerformWhenApplicationEntersForeground&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This initializer also implements the &lt;code&gt;shouldPerformWhenApplicationEntersForeground&lt;/code&gt; optional method. This method allows initializers to let the application delegate know they should also be run when the application enters the foreground.&lt;/p&gt;
&lt;p&gt;Now all that is left is running the initializers every time the app launches. In your app delegate simply add the following to &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;initializers makeObjectsPerformSelector&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;performWithConfiguration&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; withObject&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Configuration defaultConfiguration&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can run initializers when the application enters the foreground by adding this to the &lt;code&gt;applicationWillEnterForeground:&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;initializers enumerateObjectsUsingBlock&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Initializer&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; initializer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NSUInteger idx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BOOL &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;stop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;initializer respondsToSelector&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;shouldPerformWhenApplicationEntersForeground&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;initializer shouldPerformWhenApplicationEntersForeground&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;initializer performWithConfiguration&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Configuration defaultConfiguration&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In both examples &lt;code&gt;self.initializers&lt;/code&gt; is an array of initializers. In the Karma app the property is implemented like this:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSArray &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;initializers&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;_initializers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        _initializers &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;LoggingInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;HockeyInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;WontonInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;FacebookInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;StoryboardInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;StoreInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;APNInitializer alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _initializers&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By encapsulating initialization logic into it&#39;s own object you can keep the application delegate just that much cleaner. If by this point you&#39;re wondering what that configuration argument really is. Be patient. That will be the subject of a next post.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Adopting a new programming language</title>
    <link href="https://annema.me/blog/archive/2014-07-02-adopting-a-new-programming-language/" />
    <updated>2014-07-02T17:33:00Z</updated>
    <id>https://annema.me/blog/archive/2014-07-02-adopting-a-new-programming-language/</id>
    <content type="html">&lt;p&gt;Over the course of my short career I&#39;ve had the opportunity to build production-quality software in many new languages. I &lt;em&gt;like&lt;/em&gt; learning new languages. I think it makes me a better developer. My skill level is probably average in most of the languages I’ve worked with, but I&#39;ve learned something useful from each and every one.&lt;/p&gt;
&lt;p&gt;Here&#39;s my approach to adopting a new language.&lt;/p&gt;
&lt;h2&gt;Commit!&lt;/h2&gt;
&lt;p&gt;There’s no use in trying to adopt something if the language you’re comfortable with is looming nearby: have a specific goal in mind and commit to it. Write a program, write a single class, do a beginners tutorial. Anything, as long as it commits you to writing the new language and nothing else.&lt;/p&gt;
&lt;h2&gt;Stay idiomatic&lt;/h2&gt;
&lt;p&gt;Most programmers I know, including myself, will come to a new language and start complaining about what it lacks. Most of us will also immediately start looking for ways to incorporate the favorite features from our language of choice.&lt;/p&gt;
&lt;p&gt;Avoid this at all costs. People are productive in the language every day. It is very likely they have a better, more idiomatic, solution for the problem you&#39;re trying solve. Don&#39;t try to get back into your comfort zone by turning a language into something it&#39;s not. You want to learn something new, not force your old knowledge into another context.&lt;/p&gt;
&lt;h2&gt;Learn when you have a better solution&lt;/h2&gt;
&lt;p&gt;Eventually you&#39;ll become comfortable in a language. You&#39;ll know which solutions have been tried and which don&#39;t work for you. This is the point to start incorporating past experiences, never earlier. Note that it can take months, if not years, to get to this level of proficiency. If you&#39;re not sure, you&#39;re not ready yet.&lt;/p&gt;
&lt;p&gt;Side note: I&#39;m talking about language patterns that apply to specific languages. You should always try to follow good software practices. Regardless of language you should always be on the lookout for &lt;a href=&quot;http://en.wikipedia.org/wiki/Law_of_Demeter&quot;&gt;Law of Demeter&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Lyskov&lt;/a&gt; violations.&lt;/p&gt;
&lt;h2&gt;Learn the frameworks&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Programming languages are born, evolve and are discarded. Knowing the big concepts will help you transition to any new language. — &lt;a href=&quot;https://twitter.com/casademora/status/476755756612476931&quot;&gt;Saul Mora&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most programming languages have similar syntax, so learning the syntax usually isn&#39;t the hardest part. Unless you&#39;re designing a language, it doesn&#39;t really matter how a method is called.
It&#39;s the frameworks where you have the most opportunity to learn about new patterns, or novel ways to use them.&lt;/p&gt;
&lt;p&gt;One trick I picked up to learn is to take warnings seriously. It&#39;s easy to ignore warnings when learning a new language. Especially early on, you might not yet really know what is going on, and the warnings might be very cryptic and hard to understand. Don&#39;t ignore them. Warnings are meant to tell you about a potential problem, an issue that is likely to cause a bug at some point. Only ignore them if you truly know what you&#39;re doing.&lt;/p&gt;
&lt;p&gt;Warnings give you an opportunity to learn something new. Frameworks often warn about using it in ways that might become problematic. By exploring these warnings, you learn a little about the assumptions and inner workings of the framework. Only after learning what the warning means should you decide to ignore the warning.&lt;/p&gt;
&lt;h2&gt;Become part of the community&lt;/h2&gt;
&lt;p&gt;When you first get started, you might not know anybody in that community. That means there’s no one to reach out to when you get stuck. It&#39;s important to find people that can help you learn.&lt;/p&gt;
&lt;p&gt;Try to go to meetups. If you&#39;re in a hub like New York, there&#39;s probably a ton. If not try, to at least go to a conference. Regardless of where you are in the world you’ll want to engage with the community online.&lt;/p&gt;
&lt;p&gt;The best way to get yourself known is speaking. It might be hard to get in, because organisers don&#39;t know you, but you do have a unique perspective now. You&#39;ve learned their language coming from a different background, and should be able to give an interesting talk about it. Talk about the challenges of adopting the language. Talk about things you find good/bad in the community. You have an unbiased view of what it&#39;s like to get started and the community can learn from that.&lt;/p&gt;
&lt;h2&gt;Learn how to navigate the docs&lt;/h2&gt;
&lt;p&gt;The documentation is your number one go-to for problems and discovery. Learning to navigate the documentation means you can find things faster. Most community-maintained frameworks also adopt the documentation style and design of the language. For example, most Ruby documentation looks like, well, &lt;a href=&quot;http://ruby-doc.org/&quot;&gt;ruby doc&lt;/a&gt;. By just learning to navigate the language&#39;s docs, you&#39;re simultaneously getting familiar with how most of the community documents their code.&lt;/p&gt;
&lt;h2&gt;Embrace the change&lt;/h2&gt;
&lt;p&gt;Initially you will literally feel overwhelmed. Programming is making choices and for the first couple of weeks you will feel like every choice you make is stupid and wrong. In short, you will have no clue what you&#39;re doing. At some point or another you probably have to suppress the urge to find whoever wrote the documentation and have a good chat with him. Don&#39;t let this feeling discourage you. You&#39;re outside of your comfort zone; you should, by definition, feel uncomfortable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: I made a bad joke about PHP. I probably thought it was funny at the time, but reading it now; it does not fit this post nor my blog. This is about encouraging everyone to learn new things and the comment detracts from that. PHP is used succesfuly every day and joking about it only disrespects its community. Linking to Buffer, a company advocating positivity and succesfully using PHP, in the same paragraph makes it even worse. I apologize. I left the comment in for posterity.&lt;/p&gt;
&lt;p&gt;We&#39;re all &lt;em&gt;software&lt;/em&gt; developers. You&#39;re not just a Ruby developer, I&#39;m not just an Objective-C developer, &lt;s&gt;and in some circles you don&#39;t want to identify yourself as a PHP developer&lt;/s&gt;. More diversity in your knowledge and your experiences means you&#39;ll be able to build more interesting things. Or as the &lt;a href=&quot;http://blog.bufferapp.com/connections-in-the-brain-understanding-creativity-and-intelligenceconnections&quot;&gt;Buffer Blog&lt;/a&gt; said it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The more of these building blocks we have, and the more diverse their shapes and colors, the more interesting our castles will become.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>Hour formatting with NSDateFormatter dateFormatFromTemplate</title>
    <link href="https://annema.me/blog/archive/2014-05-27-hour-formatting-with-nsdateformatter-dateformatfromtemplate/" />
    <updated>2014-05-27T17:00:00Z</updated>
    <id>https://annema.me/blog/archive/2014-05-27-hour-formatting-with-nsdateformatter-dateformatfromtemplate/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt; Using NSDateFormatter&#39;s &lt;code&gt;dateFormatFromTemplate:options:locale:&lt;/code&gt; for 12/24 hours? Use &amp;quot;j&amp;quot; instead of &amp;quot;h&amp;quot; or &amp;quot;H&amp;quot; for the hour format.&lt;/p&gt;
&lt;p&gt;Last week I started a fight with NSDateFormatter. I needed to format just the hour of an &lt;code&gt;NSDate&lt;/code&gt;. Formatting hours is especially tricking because unlike any other date component, the same hour can be shown in two different formats, 12 hour with am/pm designator or 24 hour.&lt;/p&gt;
&lt;p&gt;To generate the date format I&#39;m using &lt;code&gt;NSDateFormatter&lt;/code&gt;&#39;s &lt;code&gt;dateFormatFromTemplate:options:locale:&lt;/code&gt; class method. This was my first try:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSDateFormatter dateFormatFromTemplate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;HH a&quot;&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; locale&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSLocale currentLocale&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The template string uses 24 hour format but also includes the am/pm designator &#39;a&#39;. HH stands for 0 prefixed 0-23 hours. I wasn&#39;t exactly sure how to use this method but my expectation was that it would be rewritten to &amp;quot;hh a&amp;quot; and &amp;quot;HH&amp;quot; for 12 and 24 hours respectively.&lt;/p&gt;
&lt;p&gt;This appears works. On my phone (set to nl_NL and 24 hour time format), toggling the 12/24 hour setting would correctly change the generated format. In the simulator and on one of our test phones it did not. The test phone was set to 12 hour clock and it&#39;s locale was set to en_US, but &lt;code&gt;dateFromTemplate:options:locale:&lt;/code&gt; always returned &amp;quot;HH&amp;quot; as the date format.&lt;/p&gt;
&lt;p&gt;I changed the template to read &lt;code&gt;hh a&lt;/code&gt;. This again appeared to work except on my phone. Which would now always format 12 hour time. I reversed the problem.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NSDateFormatter&lt;/code&gt; is documented to try to rewrite the format to match the 12/24 hour preference in the Settings app. My guess is that this is why toggling the preference appeared to work for phones that were set to the same locale as the template string I was passing in.&lt;/p&gt;
&lt;p&gt;After googling and trying to comprehend the &lt;a href=&quot;http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns&quot;&gt;Unicode Technical Standard&lt;/a&gt; it finally clicked. I kept glossing over the last hour designator of which the first line of the description says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a special-purpose symbol. It must not occur in pattern or skeleton data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My mind would read that it shouldn&#39;t be used in pattern data and move on. Unfortunately the next line says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Instead, it is reserved for use in skeletons passed to APIs doing flexible date pattern generation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which is exactly the purpose of this NSDateFormatter API, just worded somewhat confusingly. Eventually the fix was to change the template line to:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSDateFormatter dateFormatFromTemplate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;jj&quot;&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; locale&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSLocale currentLocale&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and all was good in the world.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Builder and GCC Code Block Evaluation</title>
    <link href="https://annema.me/blog/archive/2014-05-19-builder-and-gcc-code-block-evaluation/" />
    <updated>2014-05-19T16:04:00Z</updated>
    <id>https://annema.me/blog/archive/2014-05-19-builder-and-gcc-code-block-evaluation/</id>
    <content type="html">&lt;p&gt;My post about the &lt;a href=&quot;http://www.annema.me/the-builder-pattern-in-objective-c&quot;&gt;builder pattern&lt;/a&gt; got great responses and a lot of people offered alternative solutions to the same problem. The most popular suggestion was to use &lt;a href=&quot;http://nshipster.com/new-years-2014/#gcc-code-block-evaluation-c-extension&quot;&gt;GCC Code Block Evaluation&lt;/a&gt; without the separate builder object. Using the pizza example from the previous post it looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pizza &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;builder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Pizza alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this gives the same advantages to code organization there is nothing stopping me from modifying the pizza after it&#39;s created. One of the advantages of builder is that the created object is immutable. Immutable objects are great because they can be safely used in caches or passed around between threads.&lt;/p&gt;
&lt;p&gt;But, we can improve this by combining the approach from my first post and this one. Let&#39;s take a look at an example using Foundation:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;NSURL &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    NSURLComponents &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;components &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSURLComponents alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    components&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;scheme &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;http&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    components&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;host &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;annema.me&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    components&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;the-builder-pattern-in-objective-c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;components URL&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// URL = http://annema.me/the-builder-pattern-in-objective-c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example &lt;code&gt;NSURLComponents&lt;/code&gt; is the builder object and &lt;code&gt;NSURL&lt;/code&gt; is the immutable result. The url components are nicely enclosed in their own scope making it impossible to accidentally re-use the same instance. The created URL is immutable, giving us the same advantages of builder without having to add a special constructor to the class.&lt;/p&gt;
&lt;p&gt;Even better is that this also works for any object that has a mutable counterpart (hat tip to &lt;a href=&quot;http://cocoanuts.mobi/2014/05/15/builder/&quot;&gt;Hannes Verlinde&lt;/a&gt;). For example &lt;code&gt;NSAttributedString&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt; NSAttributedString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    NSMutableAttributedString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;mutableText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSMutableAttributedString alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mutableText appendAttributedString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSAttributedString alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; initWithString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;paragraph1&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mutableText appendAttributedString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSAttributedString alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; initWithString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;paragraph2&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mutableText appendAttributedString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSAttributedString alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; initWithString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;paragraph3&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;mutableText copy&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before writing my post I had forgotten about GCC Code Block Evaluation. After the responses made me aware of the pattern I not only found it works great with builder, it&#39;s a great aide in code organization as well. Mattt Thompson summarized it better than I can:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If code craftsmanship is important to you, strongly consider making this standard practice in your work. It may look a bit weird at first, but this will very likely become common convention by the end of 2014.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I guess my adopting this practice in 2014 is one more step towards proving Mattt&#39;s statement.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>TDD - Classicists vs Mockists</title>
    <link href="https://annema.me/blog/archive/2014-04-09-tdd-classicists-vs-mockists/" />
    <updated>2014-04-09T15:26:00Z</updated>
    <id>https://annema.me/blog/archive/2014-04-09-tdd-classicists-vs-mockists/</id>
    <content type="html">&lt;p&gt;A while ago I reread Martin Fowler&#39;s classic &lt;a href=&quot;http://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;mocks aren&#39;t stubs essay&lt;/a&gt;. He does a great job of explaining the different schools of TDD. In summary it basically comes down to classicists, those that build the system from business models up and mockists who build the system from the UI down mocking lower level components that haven&#39;t been build yet.&lt;/p&gt;
&lt;p&gt;The essay got me thinking about which school I belong too. I lean to the mockist side of things, but I think it&#39;s dangerous to separate ourselves between being purely mockist or purely classicist. You probably prefer one over the other but you should use whichever best solves your problem.&lt;/p&gt;
&lt;p&gt;For example in the Karma apps we have a store where customers can buy gigabytes. When the store loads I want to verify that the buy button is displaying the price formatted as US dollars. One way of verifying this behavior is by stubbing the formatter to return a static response. In this case I consider that an implementation detail. Instead I verify that the button title is what I expect. For example the button title for a product costing $14 should be formatted as $14.00 if the locale is en-US and the currency is dollars. It should read $ 14,00 when the locale is nl-NL and the currency is dollars. This way I not only verify that the formatter is called, but also that the formatter is configured correctly.&lt;/p&gt;
&lt;p&gt;When testing what happens after products load I &lt;em&gt;would&lt;/em&gt; use a mock (actually I would use a fake, more on that later). I don&#39;t want my tests to hit the actual API because it can randomly fail and makes it complicated to test both success and failure cases. Instead I&#39;d rather stub out the API abstraction and have it return what I expect.&lt;/p&gt;
&lt;p&gt;The problem with stubbing asynchronous code is that you need to use a &lt;a href=&quot;https://github.com/jonreid/OCMockito#capturing-arguments-for-further-assertions&quot;&gt;spy&lt;/a&gt; to get access to the success and error callbacks. I haven&#39;t seen any framework, in any language, that doesn&#39;t make this process convoluted. In reality I&#39;m much more likely to use a &lt;a href=&quot;https://github.com/klaaspieter/APIClient/blob/master/Specs/APITestHTTPClient.m#L39&quot;&gt;fake implementation&lt;/a&gt; of the API abstraction. A fake will save the callbacks internally when products are requested. After my expectations are set up, I tell the fake to either &lt;a href=&quot;https://github.com/klaaspieter/APIClient/blob/master/Specs/APITestHTTPClient.m#L101&quot;&gt;fail&lt;/a&gt; or &lt;a href=&quot;https://github.com/klaaspieter/APIClient/blob/master/Specs/APITestHTTPClient.m#L77&quot;&gt;succeed&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With this approach the tests never need access to the callbacks. Fakes do introduce more, potentially buggy, code in your test suite. As long as you keep your fakes as simple as possible this should never become a major problem. Furthermore fakes, unlike real APIs, will never randomly feel (unless you use threading, luck that with good).&lt;/p&gt;
&lt;p&gt;I like Martin&#39;s essay (seriously, read it, now!) but I think it should be made more apparent that there is no one size fits all solution. You&#39;re not a classicist or a mockist. You might prefer one over the other, but you have to assess the problem and pick the right solution.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Builder pattern in Objective-C</title>
    <link href="https://annema.me/blog/archive/2014-04-04-the-builder-pattern-in-objective-c/" />
    <updated>2014-04-04T15:43:00Z</updated>
    <id>https://annema.me/blog/archive/2014-04-04-the-builder-pattern-in-objective-c/</id>
    <content type="html">&lt;p&gt;Learning Android and by extension Java has given me some new patterns to apply in my Objective-C code. The one that I&#39;m most excited about is the &lt;a href=&quot;http://en.wikipedia.org/wiki/Builder_pattern&quot;&gt;builder pattern&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The builder pattern is an object creation pattern that fits well with Java&#39;s syntax. I&#39;ve seen some adaptions to Objective-C but they all directly copy Java&#39;s implementation directly and are not very idiomatic.&lt;/p&gt;
&lt;p&gt;Let&#39;s start off with what it looks like in Java. For my &lt;a href=&quot;http://www.meetup.com/new-york-ios-developer/events/166708792/&quot;&gt;talk about applying patterns from other languages&lt;/a&gt; I used a Pizza model as an example, I&#39;ll use the same here. This is what it looks like:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot; data-language=&quot;java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Pizza&lt;/span&gt; pizza &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Pizza&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pepperoni&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mushrooms&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Think about what this would look like if you had to use a constructor. What would happen to the constructor if the restaurant decides to add more toppings or perhaps different crust types? For these kinds of objects it&#39;s easy to end up with an array of possible constructors all covering different permutations of the arguments.&lt;/p&gt;
&lt;p&gt;This is the problem the builder pattern solves. It decouples the construction of a complex object from it&#39;s representation. The builder pattern is a so called &lt;a href=&quot;http://en.wikipedia.org/wiki/Fluent_interface&quot;&gt;fluent interface&lt;/a&gt;; an API that aims to provide more readable code.&lt;/p&gt;
&lt;p&gt;A direct port to Objective-C looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pizza &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;PizzaBuilder alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; setPepperoni&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; setMushrooms&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; setSize&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; build&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not very fluent is it? Unlike others I don&#39;t mind Objective-C&#39;s square brackets but there&#39;s a limit. The following is a more idiomatic approach. It makes use of Objective-C&#39;s dot syntax to set the properties:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;PizzaBuilder &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;builder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;PizzaBuilder alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pizza &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;builder build&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This definitely reads better but we&#39;re exposing the builder beyond it&#39;s minimum scope. It&#39;s possible to accidentally re-use the same object somewhere in the same method. In general the scope of variables should always be limited to their absolute minimum.&lt;/p&gt;
&lt;p&gt;One of the most common mistakes I see when people are trying to adopt a new language is copy patterns from their favorite language and subsequently complain how bad the adopted language is. Copying the Java implementation has served us well so far but we have to let go now and make the pattern ours. Good artists copy, great artists steal.&lt;/p&gt;
&lt;p&gt;In order to make this pattern fit Objective-C we&#39;re going to apply another pattern. This one comes from Ruby. I don&#39;t know what the official name for it is, I just call it the Ruby configuration block pattern. This is our final idiomatic Objective-C implementation:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pizza &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Pizza pizzaWithBlock&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PizzaBuilder &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We made the interface fluent, the scope of the builder is limited to within the block and as an added benefit the call to build is now implicit. When the block returns the &lt;code&gt;pizzaWithBlock:&lt;/code&gt; method knows that configuration is finished and can call build for us. Not only did we make the pattern idiomatic Objective-C, we also removed one of the Java implementation&#39;s major headaches; forgetting to call the sentinel method.&lt;/p&gt;
&lt;p&gt;To finish, this is the &lt;code&gt;pizzaWithBlock:&lt;/code&gt; method implementation:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instancetype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;pizzaWithBlock&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PizzaBuilderBlock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;block &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NSParameterAssert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;block&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    PizzaBuilder &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;builder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;PizzaBuilder alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;builder build&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The builder&#39;s &lt;code&gt;build&lt;/code&gt; method is implemented as:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Pizza &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;build&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Pizza alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; initWithBuilder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally Pizza&#39;s &lt;code&gt;initWithBuilder:&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initWithBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PizzaBuilder &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        _size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        _pepperoni &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pepperoni&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        _mushrooms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mushrooms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use a similar approach in &lt;a href=&quot;https://github.com/klaaspieter/APIClient/blob/master/Classes/APIClientConfiguration.m#L28&quot;&gt;APIClient&lt;/a&gt;. Note that I wrote this code before I knew about the builder pattern so it isn&#39;t an exact implementation. Having read this post you should now be able to &lt;a href=&quot;https://github.com/klaaspieter/APIClient/pulls&quot;&gt;improve my implementation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I believe we can learn a lot from other languages and their communities. Unfortunately most of us don&#39;t have the time to really adopt a new language. This post serves as a shortcut. You just learned a new pattern to apply in your Objective-C code without first having to learn Java or Ruby.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Android adventures #3 - Testing</title>
    <link href="https://annema.me/blog/archive/2014-04-02-android-adventures-3-testing/" />
    <updated>2014-04-02T15:14:00Z</updated>
    <id>https://annema.me/blog/archive/2014-04-02-android-adventures-3-testing/</id>
    <content type="html">&lt;p&gt;Due to an injury I had to suspend training for my first &lt;a href=&quot;http://www.nyrr.org/races-and-events/2014/nyrr-five-borough-series-brooklyn-half&quot;&gt;half marathon&lt;/a&gt; for the remainder of the week. I found myself with some extra time yesterday morning. I decided to spend that time on trying to set up testing for the Karma Android app.&lt;/p&gt;
&lt;p&gt;Honestly testing on Android is about the same state as Objective-C when I started 5(?) years ago. At Karma we test most of our code (including our iOS app) but early on we made the decision not to test our Android app. Because of my inexperience with Android learning the platform and learning how to write test for it would&#39;ve just taken too much time.&lt;/p&gt;
&lt;p&gt;I&#39;ve been doing Android for a couple of months now and felt more confident that I could figure it out. If you, like me this morning, have no idea where to get started I highly recommend &lt;a href=&quot;http://rexstjohn.com/unit-testing-with-android-studio/&quot;&gt;this article&lt;/a&gt;. Using this article I got it working. I immediately started writing tests for components that most need it.&lt;/p&gt;
&lt;p&gt;The first thing I noticed is how slow tests are. Practicing BDD/TDD requires a fast test suite but the gradle build/test step takes quite some time on my state of the art MacBook Pro. This is with just one unit test, I can only imagine how slow it&#39;ll get when I get to the level of coverage that our iOS app has. Slow tests, in this case, are better than no tests so I patiently endured.&lt;/p&gt;
&lt;p&gt;The second unit test I wrote required a mock. I&#39;m a big fan of &lt;a href=&quot;http://www.annema.me/why-i-prefer-testing-with-specta-expecta-and-ocmockito&quot;&gt;OCMockito&lt;/a&gt; for iOS and I decided to try &lt;a href=&quot;https://code.google.com/p/mockito/&quot;&gt;Mockito&lt;/a&gt;. This is where things got hard. Googling gives me a lot of outdated and conflicting information. I&#39;m assuming all the suggestions worked at some point in Android&#39;s Studio lifecycle but they sure as hell don&#39;t anymore.&lt;/p&gt;
&lt;p&gt;Here are some of the things I tried:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This answer on &lt;a href=&quot;http://stackoverflow.com/a/16637755/1555903&quot;&gt;StackOverflow&lt;/a&gt;. It fails with an error that &lt;code&gt;instrumentTestCompile&lt;/code&gt; doesn&#39;t exist.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing&quot;&gt;linked documentation&lt;/a&gt; suggests using &lt;code&gt;androidTestCompile &amp;quot;org.mockito:mockito-core:1.9.5&amp;quot;&lt;/code&gt;. This worked but adding the static import for mockito still failed.&lt;/li&gt;
&lt;li&gt;I believe this &lt;a href=&quot;https://plus.google.com/+AndroidDevelopers/posts/Xw8qbKRwMxx&quot;&gt;Google Plus&lt;/a&gt; post was linked in the last Android Weekly newsletter. It&#39;s a variation on the above and also didn&#39;t work.&lt;/li&gt;
&lt;li&gt;Tried following the &lt;a href=&quot;http://tools.android.com/tech-docs/new-build-system/user-guide&quot;&gt;Gradle user guide&lt;/a&gt;. It constantly refers to things mentioned in previous chapters making it really hard to get just the information I need. I intend to read it at some point, but did not have the time yesterday morning.&lt;/li&gt;
&lt;li&gt;More googling found me yet another project from &lt;a href=&quot;https://github.com/JakeWharton/gradle-android-test-plugin&quot;&gt;Jake Wharton&lt;/a&gt;. Unfortunately it&#39;s deprecated. There are successors I believe but I get the feeling that this is already part of Android Studio now?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Trying to combine different solutions from different blogs all stating that &lt;em&gt;theirs&lt;/em&gt; is the way to go took me a couple of hours and resulted in nothing.&lt;/p&gt;
&lt;p&gt;I only just started Android but I consider the lack of good up-to-date articles a huge problem. This wasn&#39;t my first goose chase through Android blogs all recommending different things. I find the official Android documentation thorough in documenting specific APIs, but it often lacks recommended usage and best practices. When starting a new technology you need someone to tell you how it&#39;s supposed to be done. I was lucky to have some experienced developers advising me, but not every beginner has that luxury.&lt;/p&gt;
&lt;p&gt;On the bright side, I appreciate Apple&#39;s &lt;a href=&quot;https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html&quot;&gt;very&lt;/a&gt; &lt;a href=&quot;https://developer.apple.com/library/Mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html&quot;&gt;thorough&lt;/a&gt; &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/userexperience/conceptual/tableview_iphone/AboutTableViewsiPhone/AboutTableViewsiPhone.html&quot;&gt;guides&lt;/a&gt; a lot more now.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Android adventures #2 - The first crash</title>
    <link href="https://annema.me/blog/archive/2014-03-31-android-adventures-2-the-first-crash/" />
    <updated>2014-03-31T15:12:00Z</updated>
    <id>https://annema.me/blog/archive/2014-03-31-android-adventures-2-the-first-crash/</id>
    <content type="html">&lt;p&gt;Last week we introduced bug fix monday&#39;s at Karma. The goal is to have a dedicated day to fix bugs that we usually don&#39;t have time for. Because, you know, features are better.&lt;/p&gt;
&lt;p&gt;In Android I&#39;ve had a crasher for a while that falls into this category. With every release I classify it as a nice to have and end up not getting around to it. On the first bug fix monday I decided to tackle it. Problem is I have no clue why it happens.&lt;/p&gt;
&lt;p&gt;Luckily the code was also in need of a refactor. Without a reliable way to reproduce I hope the refactor fixed the problem, but if it doesn&#39;t I found some useful features in Crashlytics to help with debugging.&lt;/p&gt;
&lt;p&gt;First, instead of crashing I catch the NullPointerException causing the crash and use &lt;a href=&quot;http://support.crashlytics.com/knowledgebase/articles/202805-logging-caught-exceptions&quot;&gt;&lt;code&gt;Crashlytics.logException(e);&lt;/code&gt;&lt;/a&gt; to send it as a non-fatal crash. This gives me the same information as I currently have, but without affecting the user.&lt;/p&gt;
&lt;p&gt;I dislike catching unchecked exceptions though because I could be hiding a different problem too. In order to actually fix (instead of hide) the issue I&#39;ll need more information.&lt;/p&gt;
&lt;p&gt;My assumption is that the crasher is related to the Fragment lifecycle thus I want to know more about it&#39;s state when the crash happens. The &lt;code&gt;Fragment&lt;/code&gt; class has method called [&lt;code&gt;dump&lt;/code&gt;](http://developer.android.com/reference/android/app/Fragment.html#dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[])) but it&#39;s usage is a bit obscure to a beginning Java developer like myself. It took some googling and trial and error but this is the working solution:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot; data-language=&quot;java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;ByteArrayOutputStream&lt;/span&gt; outputStream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ByteArrayOutputStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PrintWriter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;outputStream&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Crashlytics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;TAG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; outputStream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This writes information about fragment to an output stream which is then logged as a string. Crashlytics will write this to LogCat and also &lt;a href=&quot;http://support.crashlytics.com/knowledgebase/articles/120066-how-do-i-use-logging&quot;&gt;send it with the crash report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully the crasher has been fixed but if it isn&#39;t I&#39;ll definitely have more data to diagnose it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Android adventures #1 — Perform task on launch</title>
    <link href="https://annema.me/blog/archive/2014-03-27-android-adventures-1-perform-task-on-launch/" />
    <updated>2014-03-27T16:54:00Z</updated>
    <id>https://annema.me/blog/archive/2014-03-27-android-adventures-1-perform-task-on-launch/</id>
    <content type="html">&lt;p&gt;I&#39;m going to try and apply the &lt;a href=&quot;http://inessential.com/&quot;&gt;Brent Simmons&lt;/a&gt; approach to Android development. This is the first installment.&lt;/p&gt;
&lt;p&gt;I need a way to do something when my Android app is launched. Most Google results I find are about getting notified when another app launches. I&#39;m just interested in when my app launches because I need to load the user&#39;s authorization token from disk and create the session.&lt;/p&gt;
&lt;p&gt;I realize that most of my readers probably do iOS so let me explain why this is hard. On iOS there is the AppDelegate. Whenever your app launches that&#39;s where you do these kinds of common setup. Android apps consists of 1 or more Activities. Every activity is a completely decoupled component that can be launched separately. In other words when the StoreActivity opens there is no guarantee that the MainActivity or any other activity was started before that. In a way you can see Android activities as the AppDelegate and a ViewController merged into the same thing.&lt;/p&gt;
&lt;p&gt;Back to the problem at hand. &lt;em&gt;A&lt;/em&gt; solution would be to use an abstract superclass for every activity and have that manage creating the session in &lt;code&gt;onCreate:&lt;/code&gt;. I dislike this because what to do when I need a &lt;a href=&quot;http://developer.android.com/reference/android/app/ListActivity.html&quot;&gt;&lt;code&gt;ListActivity&lt;/code&gt;&lt;/a&gt;. I can&#39;t dynamically change the superclass of a built-in activity (Technically I probably could, it just sounds like a bad idea). Another reason is that I already have an abstract superclass. Every activity in the &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.yourkarma.android&quot;&gt;Karma app&lt;/a&gt; needs to monitor the hotspot status and update the background color accordingly. Now I would need a &lt;code&gt;AbstractHotspotActivity&lt;/code&gt; and a &lt;code&gt;AbstractSessionActivity&lt;/code&gt; which inherits from that? The other way around wouldn&#39;t work because not &lt;em&gt;every&lt;/em&gt; activity can be launched without going through the MainActivity first. &lt;a href=&quot;http://www.tutorialspoint.com/ruby/ruby_modules.htm&quot;&gt;Mixins&lt;/a&gt; where are you when I need you?&lt;/p&gt;
&lt;p&gt;Another solution is to subclass Application and setup the session there. &lt;a href=&quot;http://kevinthebigapple.tumblr.com/&quot;&gt;Experienced Android developers&lt;/a&gt; tell me the Application methods are guaranteed to be called before anything else in your application. I can&#39;t explain it, but I also dislike this approach. It might be because when I started doing iOS (a long time ago) it was acceptable to put global state on the AppDelegate so that you can reach it using: &lt;code&gt;UIApplication sharedApplication].delegate.someProperty&lt;/code&gt;. In the Android community subclassing Application is an &lt;a href=&quot;http://stackoverflow.com/a/708317/1555903&quot;&gt;acceptable solution&lt;/a&gt; for the same thing. I suspect my iOS attuned nose is just picking up the stale smell of buried corpses.&lt;/p&gt;
&lt;p&gt;Unfortunately I haven&#39;t found another solution so I&#39;m going to choose the lesser of two evils here. I&#39;m going to subclass Application and deal with it. Chances are future-me will have to write another post about this. Future-me, if you&#39;re reading this, deal with it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Pomodoro Technique</title>
    <link href="https://annema.me/blog/archive/2014-03-25-the-pomodoro-technique/" />
    <updated>2014-03-25T17:04:00Z</updated>
    <id>https://annema.me/blog/archive/2014-03-25-the-pomodoro-technique/</id>
    <content type="html">&lt;p&gt;A while ago I started working with &lt;a href=&quot;http://pomodorotechnique.com/&quot;&gt;The Pomodoro Technique&lt;/a&gt;. I initially had my reservations but after using it semi-consistently for a couple of months I don&#39;t see myself going back.&lt;/p&gt;
&lt;p&gt;Pomdoro is a time management method named after the kitchen timer. The basic premise is that you decide on a task to work on, set the timer at 25 minutes and exclusively work on that task. When 25 minutes have elapsed you take a short 5 minute break and start the next.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://mechanicaldelay.com/wp-content/uploads/2013/06/6a00d83454b21e69e2017743ac59f5970d-800wi.png&quot; alt=&quot;Pomodoro Kitchen Timer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Pomodoro kitchen timer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Initially I had problems adopting it because I had a wrong definition for a task. For me, a task had to be something I could finish in 25 minutes. Most programming tasks don&#39;t fall into that category. Eventually I settled on a different definition: a task is something to work on exclusively for the next 25 minutes. It doesn&#39;t matter if I finish it in that time, I just want to commit myself to doing that one thing for a specific amount of time. If I do finish I pick the next task of my todo list and continue with that until the 25 minutes are up.&lt;/p&gt;
&lt;p&gt;My average work day now consists of three recurring tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Programming, what I get paid to do, so basically what I do when not doing anything else;&lt;/li&gt;
&lt;li&gt;Email, 1 Pomodoro somewhere after lunch;&lt;/li&gt;
&lt;li&gt;Write, 1 Pomodoro immediately after lunch;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I keep up to date with what&#39;s going on in the world during the 5 minute breaks. The point is to eliminate distractions so I try not to check IM, Twitter or Facebook during the 25 minutes.&lt;/p&gt;
&lt;p&gt;It&#39;s impossible to measure if using Pomodoro has made me more productive, but I &lt;em&gt;feel&lt;/em&gt; more productive. Heck, I literally shipped an &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.yourkarma.android&quot;&gt;Android app&lt;/a&gt; with no prior Android development experience in 4 weeks.&lt;/p&gt;
&lt;p&gt;Pomodoro also gives me a way to measure my productivity. Honestly I don&#39;t really care about how much time I spend on programming. Some days are bad, that&#39;s what you get when you&#39;re doing creative work. With other tasks like email though it helps me constrain the amount of time I spend on it. Even on a bad day I know I&#39;ll never get distracted by email for more than 25 minutes. Also if doing email starts taking more than 25 minutes I know it&#39;s time to change something.&lt;/p&gt;
&lt;p&gt;Like everything else, it isn&#39;t all perfect. It&#39;s hard not to get distracted when working in an office. A co-worker can distract you at any moment. The &lt;a href=&quot;http://pomodorotechnique.com/book/&quot;&gt;official book&lt;/a&gt; says to be strict, because whoever is interrupting you can usually wait. I just don&#39;t like blowing people off like that. Besides interacting with co-workers should be fun and an important part of any office culture.&lt;/p&gt;
&lt;p&gt;Office culture also prevents me from taking the longer breaks. The technique suggests taking a break every 4 Pomodoros. We do lunch together at the Karma office and our lunch time rarely coincides exactly with 4 Pomodoros. I basically take my first long break during lunch and usually another one somewhere in the afternoon. They&#39;re rarely exactly every 2 hours though.&lt;/p&gt;
&lt;p&gt;I&#39;ve been doing Pomodoro consistently for a while now and I&#39;m not going back to my old way of working. I realize now how much time I actually spent being distracted. Programming often requires keeping a complex model in your head &lt;a href=&quot;http://ubuntuone.com/27zU9Q5Tlqkoohp6cO4sF2&quot;&gt;and that&#39;s gone the second you do something else&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully by now you&#39;re thinking about trying Pomodoro. I highly encourage you to do so. Get the &lt;a href=&quot;https://itunes.apple.com/us/app/pomodoroapp/id705103149?mt=12&quot;&gt;Pomodoro Mac app&lt;/a&gt;, commit yourself to work on something for 25 minutes and start the timer.&lt;/p&gt;
&lt;p&gt;When you&#39;re starting out, don&#39;t repeat my mistake. &lt;a href=&quot;http://en.wikipedia.org/wiki/KISS_principle&quot;&gt;Keep It Simple (Stupid)&lt;/a&gt;! According to the book Pomodoro is about much more than just 25 minutes of focused work, but that is what gives me the most value. Don&#39;t get bogged down in the details, just get started!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I recommended the Pomodoro Mac app because that&#39;s what I use and at the time of writing it was free. Even though it&#39;s a paid app now I can still recommend it, but I don&#39;t know how it stacks up against other paid Pomodoro apps.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Problems with iOS Push Notifications</title>
    <link href="https://annema.me/blog/archive/2014-02-07-problems-with-ios-push-notifications/" />
    <updated>2014-02-07T02:34:00Z</updated>
    <id>https://annema.me/blog/archive/2014-02-07-problems-with-ios-push-notifications/</id>
    <content type="html">&lt;p&gt;Push notifications are a great way to keep users engaged with your iPhone app. The amount of applications that support them led me to conclude that supporting push notification must be trivial. After implementing them myself I&#39;m left with the realization that it is most definitely not.&lt;/p&gt;
&lt;p&gt;Consider the &lt;a href=&quot;https://itunes.apple.com/us/app/id673069729?mt=8&quot;&gt;Karma iOS app&lt;/a&gt;, we have a simple use case, when a push notification is delivered the user needs to be presented the correct screen. For example when a user opens a &#39;balance&#39; notification, the app should open in the store.&lt;/p&gt;
&lt;p&gt;Starting at the beginning let&#39;s take a look at the code paths when a push notification is delivered. There are two &lt;code&gt;UIApplicationDelegate&lt;/code&gt; methods that need to be implemented. One for when the app is running and one for when it&#39;s not.&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didFinishLaunchingWithOptions&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;launchOptions&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;UIApplicationRemoteNotificationKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Handle the notification&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;launchOptions&lt;/code&gt; dictionary will contain the information about your push notification. This key won&#39;t exist if your app was launched in another way.&lt;/p&gt;
&lt;p&gt;When your app is already running you need to handle incoming notifications differently:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Handle the notification&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately we&#39;re not done yet. A running app can be running in 3 different modes: &lt;code&gt;UIApplicationStateActive&lt;/code&gt;, &lt;code&gt;UIApplicationStateInactive&lt;/code&gt; and &lt;code&gt;UIApplicationStateBackground&lt;/code&gt;. When the application state is in &lt;code&gt;UIApplicationStateActive&lt;/code&gt; the user is not automatically notified of the push notification and is likely interacting with the app. In the Karma case where we want to show a particular screen we cannot rip a user out of his workflow. The solution:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;applicationState &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; UIApplicationStateActive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Handle the notification&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s not 1, not 2, but 3 possible code paths (the conditional technically makes it 4, but we&#39;re not using else or doing anything after it) of which 2 have duplicate code. All that and we still haven&#39;t really done anything. What boggles my mind is that &lt;em&gt;every&lt;/em&gt; iOS developer implementing push notifications has to write this code every time push support is added to an app.&lt;/p&gt;
&lt;p&gt;Let&#39;s fix the duplicate code by introducing a class named &lt;code&gt;RemoteNotificationHandler&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;@interface&lt;/span&gt; RemoteNotificationHandler
&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;notification&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait, you just moved the method to a different object? Yep! How is that going to solve duplicate code? Well, take a look at the AppDelegate:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didFinishLaunchingWithOptions&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;UIApplicationRemoteNotificationKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;remoteNotificationHandler application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;UIApplicationRemoteNotificationKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;remoteNotificationHandler application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;UIApplicationRemoteNotificationKey&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is still some duplicate code, but at least we moved the bulk of handling the notification to an isolated place that can be independently tested. Note that the check for &lt;code&gt;application.applicationState&lt;/code&gt; is gone. Now that we have an isolated object dealing with notifications this responsibility belongs there.&lt;/p&gt;
&lt;p&gt;Honestly I wish Apple would split the &lt;code&gt;UIApplicationDelegate&lt;/code&gt; protocol up into &lt;a href=&quot;https://github.com/JaviSoto/JSDecoupledAppDelegate&quot;&gt;different protocols&lt;/a&gt;. That way I don&#39;t have to spend so much time keeping my AppDelegate short and readable. Something like &lt;code&gt;application.remoteNotificationDelegate = [[RemoteNotificationHandler alloc] init]&lt;/code&gt; would be perfect (&lt;a href=&quot;https://bugreport.apple.com&quot;&gt;Radar #15940986&lt;/a&gt;). Splitting the delegate into smaller objects also means classes like the &lt;code&gt;RemoteNotificationHandler&lt;/code&gt; aren&#39;t needed anymore because the delegate objects can be tested independently from the main AppDelegate.&lt;/p&gt;
&lt;p&gt;Back to the topic at hand. Over 600 words and we haven&#39;t done anything to solve the initial use case; routing the user to the correct screen in response to a push notification.&lt;/p&gt;
&lt;p&gt;To make the problem even more interesting. In the Karma app we didn&#39;t simply require the user to be routed to a particular screen. The user needs to be routed to the relevant place in the app as if he had navigated there using the UI. We didn&#39;t want to present a modal sheet because it means the same place in the UI can be reached in more than one way. This is not only confusing to the user it also convolutes the code because the same view controller can be presented in different situations.&lt;/p&gt;
&lt;p&gt;Enough context, let&#39;s begin implementing the &lt;code&gt;RemoteNotificationHandler&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;notification&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we do anything else we need to know if the user is currently interacting with the app. If so, we&#39;re going to do nothing with the notification. We deemed this sufficient for the Karma app, if you want to simulate the iOS notification bar there are &lt;a href=&quot;http://cocoapods.org/?q=notification&quot;&gt;plenty of libraries&lt;/a&gt; out there.&lt;/p&gt;
&lt;p&gt;Next we&#39;ll show the appropriate view controller. The next example is storyboard specific. It also uses &lt;a href=&quot;https://github.com/klaaspieter/KPAStoryboardConvenience&quot;&gt;storyboard convenience&lt;/a&gt; library because, having written it myself, I like using it:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UIApplication &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;application didReceiveRemoteNotification&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSDictionary &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;notification&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token comment&quot;&gt;// Application state != Active&lt;/span&gt;

			NSString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;segueIdentifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;UIStoryboard segueIdentifierForClass&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;GuestViewController class&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;application&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rootViewController performSegue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;segueIdentifier&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, this works! Sometimes. We ask the rootViewController of the application&#39;s key window to present the &lt;code&gt;GuestViewController&lt;/code&gt; for us. This works if your storyboard&#39;s rootViewController has a segue called &lt;code&gt;GuestViewControllerSegue&lt;/code&gt;. If the view controller responsible for presenting the guest screen is deeper down into your view controller stack this approach will quickly turn into a mess of &lt;code&gt;rootViewController.presentedViewController.topViewController&lt;/code&gt;. This approach will also break when the rootViewController is already presenting a different view controller.&lt;/p&gt;
&lt;p&gt;I dislike this approach because it&#39;s a clear &lt;a href=&quot;http://en.wikipedia.org/wiki/Law_of_Demeter&quot;&gt;Law of Demeter&lt;/a&gt; violation. Our &lt;code&gt;RemoteNotificationHelper&lt;/code&gt; has to know about the structure of UIApplication, UIWindow and the rootViewController. If you ever decide to move things around in your app this will most definitely break. Our remote notification handler shouldn&#39;t know anything about UIWindow or UIViewController, but due to the isolated nature of view controllers this seems the only method that always works.&lt;/p&gt;
&lt;p&gt;In my attempts to make this better I tried two other methods with varying success; using the responder chain and &lt;code&gt;NSNotification&lt;/code&gt;. These both are conceptually better solutions because the part of the application interested in the remote notification gets a chance to handle it. Unfortunately the responder chain approach doesn&#39;t work because there is no guarantee that the responsible part is participating in the responder chain when the push notification is received. The &lt;code&gt;NSNotification&lt;/code&gt; approach only works if the handler of the notification is guaranteed to be in memory. If it isn&#39;t, the push notification will not be delivered. Another disadvantage of the &lt;code&gt;NSNotification&lt;/code&gt; approach is that a component cannot mark a notification as handled. You can easily get into a situation where multiple parts of your app are doing conflicting things in response to the same push notification.&lt;/p&gt;
&lt;p&gt;In the Karma app I eventually went with the &lt;code&gt;NSNotification&lt;/code&gt; approach. I know that the receiver of the notification is always in memory making this approach viable. It also nicely decouples receiving and handling the push notification, making it trivial to test both.&lt;/p&gt;
&lt;p&gt;I&#39;ve long doubted wether to post this blog post or not. The entire process of supporting push notifications seems too convoluted to be true and even now, while writing this, I feel like I must be missing something. If that is the case than please &lt;a href=&quot;https://twitter.com/klaaspieter&quot;&gt;tell me&lt;/a&gt;. If not then this will serve as an indication to others. No, you are not stupid!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Why I prefer testing with Specta, Expecta and OCMockito</title>
    <link href="https://annema.me/blog/archive/2014-01-22-why-i-prefer-testing-with-specta-expecta-and-ocmockito/" />
    <updated>2014-01-22T18:20:00Z</updated>
    <id>https://annema.me/blog/archive/2014-01-22-why-i-prefer-testing-with-specta-expecta-and-ocmockito/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;Update August 2014&lt;/strong&gt;: Since writing this article, OCMock has released major version 3. Everything said about OCMock is based on version 2.&lt;/p&gt;
&lt;p&gt;If you&#39;re testing your Objective-C code (you should) you&#39;ve probably heard of &lt;a href=&quot;https://github.com/allending/Kiwi&quot;&gt;Kiwi&lt;/a&gt; and XCTest. Great! Do you like it? Awesome! You should switch to &lt;a href=&quot;https://github.com/specta/specta&quot;&gt;Specta&lt;/a&gt; and &lt;a href=&quot;https://github.com/specta/expecta&quot;&gt;Expecta&lt;/a&gt;. Why? Keep reading.&lt;/p&gt;
&lt;h2&gt;Uniform interface&lt;/h2&gt;
&lt;p&gt;Specta provides one uniform interface that works for every kind of value. For example:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;equals YES&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isHidden&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;YES&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Yes, I&#39;m aware there is a isTruthy matcher but that wouldn&#39;t really prove my point...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare this to the Kiwi alternative:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;equals YES&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;theValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isHidden&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; should&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; equal&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;theValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;YES&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Kiwi, when working with scalars, both sides need to be wrapped using the &lt;code&gt;theValue(aScalar)&lt;/code&gt; macro. Specta hides this complexity by providing one uniform interface for any value. Anything you pass to &lt;code&gt;expect&lt;/code&gt; or to a matcher is automatically wrapped for you.&lt;/p&gt;
&lt;p&gt;If that doesn&#39;t convince you; both Kiwi and Specta are based on RSpec and RSpec &lt;a href=&quot;http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax&quot;&gt;switched&lt;/a&gt; to the &lt;code&gt;expect&lt;/code&gt; approach that Specta is using.&lt;/p&gt;
&lt;p&gt;This is their reasoning behind the change, replace RSpec with Kiwi and object with &lt;code&gt;NSObject&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The underlying problem is RSpec&#39;s should syntax: for should to work properly, it must be defined on every object in the system… but RSpec does not own every object in the system and cannot ensure that it always works consistently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Asynchronous Testing&lt;/h2&gt;
&lt;p&gt;Testing asynchronous code with Specta and Expecta is amazingly well done. It&#39;s probably my favorite feature. Both Specta and Expecta support a different use case, which combined will cover all your asynchronous testing needs.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at Specta first:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;does something asynchronously&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;AsyncBlock&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;object doSomethingAsynchronously&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BOOL wasDone&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wasDone&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beTruthy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;AsyncBlock&lt;/code&gt; is a macro that provides a block named done. You call this block whenever your test finishes. This can be anywhere between immediately or 10 seconds from now. After 10 seconds it is assumed done will not get called and your test fails. You can use this to test that some sort of callback will be called some time from now.&lt;/p&gt;
&lt;p&gt;This also works on &lt;code&gt;before&lt;/code&gt; blocks. For example to ensure that a view controller is presented before any expectations run:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;AsyncBlock&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_mainViewController presentViewController&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;_viewController animated&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;YES completion&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;done&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be careful with this approach. If you&#39;re doing TTD or BDD you want your test suite to be fast. A 10 second timeout can significantly slow it down. The Specta approach is often useful in lower levels of the stack. For example imagine AFNetworking using this approach to verify that a completion block is called after a request finishes.&lt;/p&gt;
&lt;p&gt;When you test higher up the stack you&#39;ll also want to test the outcome of the asynchronous callback. For example that the completion of a network request updates your UI:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;sets the user&#39;s name when the user loads&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user load&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nameLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;will&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Ben Day&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This verifies that the &lt;code&gt;nameLabel&lt;/code&gt;&#39;s text property equals Ben Day within 1 second. The default timeout of 1 second can be changed using &lt;code&gt;[Expecta setAsynchronousTestTimeout:2]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In my experience the combination of these methods of asynchronous testing cover any use case you might have.&lt;/p&gt;
&lt;h2&gt;Separation of concern&lt;/h2&gt;
&lt;p&gt;Specta itself is a test runner built on top of XCTest with a BDD-style DSL. Because it nicely separates concerns it does not force a particular matcher framework on you. The authors recommend you use Expecta but if you want you can also use XCTest or &lt;a href=&quot;https://github.com/hamcrest/OCHamcrest&quot;&gt;OCHamcrest&lt;/a&gt; matchers. Of course you can else write &lt;a href=&quot;https://github.com/dblock/ios-snapshot-test-case-expecta&quot;&gt;your&lt;/a&gt; &lt;a href=&quot;https://github.com/klaaspieter/UISpecta&quot;&gt;own&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Mocking (and more about separation of concerns)&lt;/h2&gt;
&lt;p&gt;Initially separation of concern was what I disliked about Specta. Not in the literal sense, who doesn&#39;t like nicely separated concerns right? The reason I initially didn&#39;t switch from Kiwi to Specta was because Kiwi comes with great mocking built-in. In other words Kiwi mixes multiple concerns into the same framework while Specta doesn&#39;t. When I realized I wasn&#39;t switching because of something I actually liked about Specta I started looking for a new mocking framework.&lt;/p&gt;
&lt;p&gt;My first pick was &lt;a href=&quot;http://ocmock.org/&quot;&gt;OCMock&lt;/a&gt;. Mostly because it&#39;s recommend by Specta&#39;s authors. OCMock was sufficient while my test suite was still small, but as it grew it quickly became a burden. It&#39;s API doesn&#39;t blend very well with Specta&#39;s BDD style and it doesn&#39;t report test failures properly. OCMock reports test failures by raising exceptions. Exceptions often do not contain enough information for the test reporter to give you accurate line and file information. When you&#39;re working with multiple mocks in the same file it becomes very hard to figure out which one is failing.&lt;/p&gt;
&lt;p&gt;After a brief search for another mocking framework I settled on &lt;a href=&quot;https://github.com/jonreid/OCMockito&quot;&gt;OCMockito&lt;/a&gt; and I&#39;ve been using it without complaints ever since. Take a look at the following spec:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;has a dependency that does something&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     _subject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dependency &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Dependency class&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;_subject doSomethingWithDependency&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_subject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dependency&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; doSomething&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OCMockito&#39;s clever use of macros make it a very good match with Specta. It also correctly reports errors making it trivial to track down the exact location of a failure.&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Historically Objective-C developers don&#39;t have a very good track record when it comes to testing. If you take a look at a language like Ruby where testing is at the core of community you&#39;ll find that better tooling, frameworks and education is what drives new rubiests to adopt that mindset.&lt;/p&gt;
&lt;p&gt;I think the introduction of tools like Cocoapods and frameworks like Specta and Expecta are the first steps in bringing that mindset to Objective-C. All we need now is more education.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Initializing Objective-C classes with sane initial state</title>
    <link href="https://annema.me/blog/archive/2014-01-14-initializing-objective-c-classes-with-sane-initial-state/" />
    <updated>2014-01-14T17:54:00Z</updated>
    <id>https://annema.me/blog/archive/2014-01-14-initializing-objective-c-classes-with-sane-initial-state/</id>
    <content type="html">&lt;p&gt;Because Objective-C has the concept of &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/Initialization/Initialization.html#//apple_ref/doc/uid/TP40010810-CH6-SW3&quot;&gt;designated initializers&lt;/a&gt;, you have to ensure your classes are instantiated using sane initial state. Take for example a fictitious person class with the designated initializer &lt;code&gt;initWithName:&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;@implementation&lt;/span&gt; Person
&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;initWithName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        _name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now in a view controller this happens:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;viewWillAppear&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BOOL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;animated&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt; viewWillAppear&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;animated&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    Person &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Person alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nameLabel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The author accidentally forgot to use the designated initializer and the program now has incorrect state. In this particular situation it results in an empty label that might or might not be visible to the user. This is a simple example but in a complex application this can easily lead to hard to find bugs.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look an Foundation class to find a solution. Specifically a possible implementation of the NSNumberFormatter &lt;code&gt;init&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;init&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; initWithLocale&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;NSLocale currentLocale&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If possible you should always prefer a sane default over an exception. Unless otherwise specified, an NSNumberFormatter is initialized with the current locale.&lt;/p&gt;
&lt;p&gt;However more often than not such a sane default doesn&#39;t exist. In the example of our Person class there is no default name that we can fallback on. In this case use &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/macro/NSParameterAssert&quot;&gt;&lt;code&gt;NSParameterAssert&lt;/code&gt;&lt;/a&gt;. Not providing a name is a programmer error. By convention any programmer error should raise an exception. &lt;code&gt;NSParameterAssert&lt;/code&gt; will conveniently do this if the passed in parameter evaluates to false.&lt;/p&gt;
&lt;p&gt;Let&#39;s see what that looks like in our Person class:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;@implementation&lt;/span&gt; Person
&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;init&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; initWithName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;nil&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;initWithName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NSParameterAssert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        _name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This 100% guarantees that your classes initial state is correct. If, like in our previous example, &lt;code&gt;init&lt;/code&gt; is accidentally used it will immediately raise an &lt;code&gt;NSInternalInconsistencyException&lt;/code&gt;. Furthermore if you remove assertions from your production code this will, apart from the fact the the application now has incorrect state, have no effect on your user&#39;s experience.&lt;/p&gt;
&lt;p&gt;This also works for classes that already have a designated initializer like UIView:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// In a UIView subclass&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;initWithFrame&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CGRect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;frame&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; initWithText&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;initWithText&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSString &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NSParameterAssert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    CGRect textFrame &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Assume this exists&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt; initWithFrame&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;textFrame&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        _text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally the initialization code paths are trivial to test:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Person&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;cannot be created without a name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            Person &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Person alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;raise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NSInternalInconsistencyException&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

       &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;can be created with a name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Person &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Person alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; initWithName&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Ender&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Ender&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There you have it. A simple and reusable way to make sure your classes are always initialized with sane initial state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;The initial version of this post included a statement that you should remove assertions from your production code. While I am still off this opinion &lt;a href=&quot;https://twitter.com/__block/status/423716919037136896&quot;&gt;@__block&lt;/a&gt; pointed out an interesting article from &lt;a href=&quot;https://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html&quot;&gt;Mike Ash&lt;/a&gt; explaining proper usage of asserts. Mike also makes a good case on why you shouldn&#39;t compile out assertions. Since this discussion is outside of the scope of this article I removed the statement.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Appreciating real world interaction</title>
    <link href="https://annema.me/blog/archive/2013-03-05-appreciating-real-world-interaction/" />
    <updated>2013-03-05T07:18:00Z</updated>
    <id>https://annema.me/blog/archive/2013-03-05-appreciating-real-world-interaction/</id>
    <content type="html">&lt;p&gt;Moving to New York and having to quickly adept to a completely different culture has really opened up my eyes to a lot of beautiful interactions we encounter during our everyday lives. This inspired me to start &lt;a href=&quot;http://realworlddetails.com&quot;&gt;realworlddetails.com&lt;/a&gt; to celebrate some of the great interactions we tend to overlook because of our busy lives.&lt;/p&gt;
&lt;p&gt;As a software user, and developer; I&#39;ve come to enjoy &lt;a href=&quot;http://littlebigdetails.com/&quot;&gt;consuming&lt;/a&gt; and &lt;a href=&quot;http://littlebigdetails.com/post/43078037323/karma-when-searching-on-the-infamous-90210-zip#_=_&quot;&gt;creating&lt;/a&gt; these fun details. Some of these details truly make our lives easier, while others are just for fun. Regardless, they will all put a smile on your face when you become aware of them. With &lt;a href=&quot;http://realworlddetails.com&quot;&gt;realworlddetails.com&lt;/a&gt;, I hope to make all of us more appreciative of the many things we encounter during our day. Whether &lt;a href=&quot;http://realworlddetails.com/post/24333231750/the-lines-at-whole-foods-are-fully-automated&quot;&gt;waiting in line&lt;/a&gt; at the grocery store, &lt;a href=&quot;http://realworlddetails.com/post/23867068143/ikea-the-color-of-the-bag-indicates-their-use&quot;&gt;shopping at Ikea&lt;/a&gt; or any other time we&#39;re not looking at a screen. Let&#39;s stop and look around for a minute.&lt;/p&gt;
&lt;p&gt;If you have any suggestions, be sure to &lt;a href=&quot;http://realworlddetails.com/submit&quot;&gt;let me know&lt;/a&gt;. You can also stay up to date by following our &lt;a href=&quot;http://realworlddetails.com&quot;&gt;Tumblr blog&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/realworlddetail&quot;&gt;Twitter&lt;/a&gt; or by simply liking our &lt;a href=&quot;https://facebook.com/realworlddetails&quot;&gt;Facebook page&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Debugging Ember</title>
    <link href="https://annema.me/blog/archive/2013-01-12-debugging-ember/" />
    <updated>2013-01-12T14:30:00Z</updated>
    <id>https://annema.me/blog/archive/2013-01-12-debugging-ember/</id>
    <content type="html">&lt;p&gt;While building the &lt;a href=&quot;https://dashboard.yourkarma.com&quot;&gt;Karma customer dashboard&lt;/a&gt; I discovered several interesting ways to debug Ember apps. Some of these are my own, others I&#39;ve taken from Tom Dale&#39;s excellent &lt;a href=&quot;http://vimeo.com/37539737&quot;&gt;debugging Ember talk&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Observers&lt;/h2&gt;
&lt;p&gt;I don&#39;t need explicit observers often in production code but I do use them frequently for debugging. Adding an observer is very similar to a computed property:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;propertyObserver&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Called when the value of property changes&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;property&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I use this when some computed property down the line has an unexpected value. Add any logging or debugging code in the observer and it will tell you whether the property is changed as expected or not.&lt;/p&gt;
&lt;h2&gt;toString&lt;/h2&gt;
&lt;p&gt;Ember does some very cool stuff to give you useful string representations of your objects. However by default modern browsers will show you the object representation. While this is often useful I find myself in situations where I just want to know what kind kind of object I&#39;m looking at.&lt;/p&gt;
&lt;p&gt;One option is to call toString on the property like so:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;applicationController&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;&amp;lt;App.ApplicationController:ember2366&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another way that is less typing is to append &amp;quot;&amp;quot; like so:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; data-language=&quot;javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;applicationController &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;&amp;lt;App.ApplicationController:ember2366&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Handlebars&lt;/h2&gt;
&lt;p&gt;Handlebars has two convenient helpers to aid in debugging. &lt;code&gt;{{log path.to.value}}&lt;/code&gt; and &lt;code&gt;{{debugger}}&lt;/code&gt; respectively log the value of the path or add a debugger statement at that location in your template.&lt;/p&gt;
&lt;h2&gt;forEach&lt;/h2&gt;
&lt;p&gt;It can be quite annoying to have to keep stepping into &lt;code&gt;forEach&lt;/code&gt; calls. Set a breakpoint inside your callback function and hit &amp;quot;continue&amp;quot;. If the array is not empty the debugger will immediately jump to your callback function. Note that the same works for any other callback as well.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://yehudakatz.com&quot;&gt;Yehuda&lt;/a&gt; adds that in Chrome you can also right click the line number and click &amp;quot;Continue to here&amp;quot;.&lt;/p&gt;
&lt;p&gt;And that&#39;s it. Tom also talks about some more generic javascript debugging techniques so I encourage you to watch it. If you have any debugging techniques I missed let me know.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>CSS Markdown mark</title>
    <link href="https://annema.me/blog/archive/2012-03-16-css-markdown-mark/" />
    <updated>2012-03-16T11:05:00Z</updated>
    <id>https://annema.me/blog/archive/2012-03-16-css-markdown-mark/</id>
    <content type="html">&lt;p&gt;I&#39;ve been impressed with icons created in CSS3 and decided to have a go at it. As an experiment I took &lt;a href=&quot;http://dcurt.is/the-markdown-mark&quot;&gt;Dustin Curtis&#39;&lt;/a&gt; markdown mark and made a version using only HTML and CSS. This is the result (&lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/CSS%20Markdown%20mark/markdown.html&quot;&gt;separate page&lt;/a&gt;):&lt;/p&gt;
&lt;style type=&quot;text/css&quot; media=&quot;screen&quot;&gt;
    .markdown {
        position:relative;
        border:10px solid gray;
        width:188px; height:108px;
        border-radius:15px;
        -webkit-font-smoothing:antialiased;
    }
    .markdown:before {
        color:gray;
        font:bold 100px &quot;Gill Sans&quot;;
        content:&quot;M&quot;;
        position:absolute;
        top:-4px;
        left:12px;
    }
    .markdown .stem {
        border:10px solid gray;
        position:absolute;
        height:30px;
        right:34px;
        top:20px;
    }
    .markdown .arrow {
        width:0;
        height:0;
        position:absolute;
        bottom:0px;
        right:14px;
        border-style:solid;
        border-width:34px 30px 20px 30px;
        border-color:gray transparent transparent transparent;
    }

    .markdown.spec {
        border-color:#ccc;
    }
    .markdown.spec:before {
        color:#ccc;
    }
    .markdown.spec .stem {
        border-color:#ccc;
    }
    .markdown.spec .arrow {
        border-top-color:#ccc;
    }

    .markdown.cutout {
        border-color:black;
    }
    .markdown.cutout:before {
        color:black;
    }
    .markdown.cutout .stem {
        border-color:black;
    }
    .markdown.cutout .arrow {
        border-top-color:black;
    }

    .markdown.solid {
        background-color:black;
        border-color:black;
    }
    .markdown.solid:before {
        color:white;
    }
    .markdown.solid .stem {
        border-color:white;
    }
    .markdown.solid .arrow {
        border-top-color:white;
    }

    /* Not part of the actual icons */
    .cutout-positioner {
        position:absolute;
        top:0px;
        left:269px;
    }

    .solid-positioner {
        position:absolute;
        top:0px;
        left:530px;
    }

    /* Make the spec background white because it doesn&#39;t really work with my blog&#39;s background */
    .markdown.spec {
        background-color:white;
    }
    /* Make the cutout background white as well, it works on my blog&#39;s background but it looks weird
    next to the specs white background */
    .markdown.cutout {
        background-color:white;
    }

&lt;/style&gt;
&lt;div style=&quot;position:relative; margin-bottom:30px;&quot;&gt;
    &lt;div class=&quot;markdown spec&quot;&gt;
        &lt;div class=&quot;stem&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;arrow&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;cutout-positioner&quot;&gt;
        &lt;div class=&quot;markdown cutout&quot;&gt;
            &lt;div class=&quot;stem&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;arrow&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;solid-positioner&quot;&gt;
        &lt;div class=&quot;markdown solid&quot;&gt;
            &lt;div class=&quot;stem&quot;&gt;&lt;/div&gt;
            &lt;div class=&quot;arrow&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Unfortunately, due to two issues in current browsers the icon is not pixel perfect.
&lt;/p&gt;
&lt;p&gt;
The M portion of the icon is rendered using the &lt;code&gt;:before&lt;/code&gt; pseudo tag with a &lt;code&gt;content&lt;/code&gt; attribute. By default text in browsers on a Mac (I haven&#39;t tested on Windows) is rendered using sub pixel antialiasing. I was able to make the drawing of the M more accurate by setting &lt;code&gt;-webkit-font-smoothing&lt;/code&gt; to &lt;code&gt;antialiased&lt;/code&gt; but the end result still has 1 pixel grayish border on both sides of the M. It should be possible to reproduce the M using CSS shapes, but that&#39;s outside the scope of my experiment.
&lt;/p&gt;
&lt;p&gt;
Note that &lt;code&gt;-webkit-font-smoothing&lt;/code&gt; also allows &lt;code&gt;never&lt;/code&gt; but the result is awful:
&lt;/p&gt;
&lt;style type=&quot;text/css&quot; media=&quot;screen&quot;&gt;
    .markdown.cutout {
        -webkit-font-smoothing:none;
    }
&lt;/style&gt;
&lt;div style=&quot;margin-bottom:30px;&quot;&gt;
    &lt;div class=&quot;markdown cutout&quot;&gt;
        &lt;div class=&quot;stem&quot;&gt;&lt;/div&gt;
        &lt;div class=&quot;arrow&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Ironically, the second issue is the lack of antialiasing on borders. Dustin&#39;s original arrow shape is very crisp whereas my version has jacked edges. The most obvious solution is to render a div with a solid background and use &lt;code&gt;:before&lt;/code&gt; and &lt;code&gt;:after&lt;/code&gt; to overlay two rotated rectangle. This would create the same effect but probably without the jacked edges. I was however unable to get this to work without the rotated rectangles overlapping others parts of the icon.
&lt;/p&gt;
&lt;p&gt;
If you know why browsers don&#39;t antialias borders or how to get the arrow more crisp; please &lt;a href=&quot;https://twitter.com/klaaspieter&quot;&gt;mention&lt;/a&gt; me on Twitter or comment on the &lt;a href=&quot;https://github.com/dcurtis/markdown-mark/pull/5&quot;&gt;pull request&lt;/a&gt;.
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Changes to AppEngine&#39;s _from_entity</title>
    <link href="https://annema.me/blog/archive/2011-09-08-changes-to-appengines-_from_entity/" />
    <updated>2011-09-08T13:49:00Z</updated>
    <id>https://annema.me/blog/archive/2011-09-08-changes-to-appengines-_from_entity/</id>
    <content type="html">&lt;p&gt;Both my blog and Enstore experienced a serious outage today. This was caused by a recent change to how App Engine initializes entities. The error was:&lt;/p&gt;
&lt;pre class=&quot;language-txt&quot; data-language=&quot;Plain text&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;BadArgumentError: Cannot use key and key_name at the same time with different values&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A common trick to detect wether an entity is loaded from datastore or not is to check &lt;code&gt;if kwargs.get(&#39;_from_entity&#39;) == True:&lt;/code&gt; in the models &lt;code&gt;__init__&lt;/code&gt; method. Before today&#39;s change _from_entity was a bool argument and this code worked perfectly. Today&#39;s change made _from_entity a dictionary containing the entities&#39; properties and values. Because of this the explicit check for &lt;code&gt;True&lt;/code&gt; returned &lt;code&gt;False&lt;/code&gt; and both Enstore and this blog started returning 500 errors.&lt;/p&gt;
&lt;p&gt;The issues were resolved by changing :&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;`&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; kwargs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;_from_entity&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;`&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot; data-language=&quot;python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;`&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; kwargs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;_from_entity&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;`&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>My git setup</title>
    <link href="https://annema.me/blog/archive/2011-04-28-my-git-setup/" />
    <updated>2011-04-28T15:30:00Z</updated>
    <id>https://annema.me/blog/archive/2011-04-28-my-git-setup/</id>
    <content type="html">&lt;p&gt;I have been using git since I started working on Cappuccino. Over time I&#39;ve found several useful additions to my configuration that made working with it easier.&lt;/p&gt;
&lt;h2&gt;Bash additions&lt;/h2&gt;
&lt;p&gt;While working with git it&#39;s easy to get lost in branches, tags and commits. The bash completion script included with git helps to keep track. It&#39;s core functionality is autocompletion, but it can optionally show the current branch after your prompt.
Installation instructions are included in the file, which you can find in the git repository under &lt;code&gt;contrib/completion/&lt;/code&gt;. If you change your bash prompt to show the current branch (step 3) consider using &lt;code&gt;PS1=&#39;&#92;h:&#92;W&#39;$RED&#39;$(__git_ps1 &amp;quot;@%s&amp;quot;)&#39;$NONE&#39;&#92;$ &#39;&lt;/code&gt;. It will display the current branch in red, making it much more obvious.&lt;/p&gt;
&lt;h2&gt;Aliases&lt;/h2&gt;
&lt;p&gt;Git (since version 1.4) includes support for aliasing commands. For a quick introduction see &lt;a href=&quot;https://git.wiki.kernel.org/index.php/Aliases&quot;&gt;this&lt;/a&gt; tutorial on the git wiki.&lt;/p&gt;
&lt;p&gt;These are the aliases I currently use:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;alias&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
	co &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; checkout
    mg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; merge
	st &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; status
	ci &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; commit
	br &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; branch
	&lt;span class=&quot;token function&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; difftool
    lg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; log &lt;span class=&quot;token parameter variable&quot;&gt;--graph&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;format:&lt;span class=&quot;token string&quot;&gt;&#39;%C(bold red)%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold green)&amp;lt;%an&gt;%Creset&#39;&lt;/span&gt; --abbrev-commit &lt;span class=&quot;token parameter variable&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;relative
	lc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; log ORIG_HEAD&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt; --no-merges &lt;span class=&quot;token parameter variable&quot;&gt;--graph&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--pretty&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;format:&lt;span class=&quot;token string&quot;&gt;&#39;%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&gt;%Creset&#39;&lt;/span&gt; --abbrev-commit &lt;span class=&quot;token parameter variable&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;relative&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the exception of &lt;code&gt;lc&lt;/code&gt; and &lt;code&gt;lg&lt;/code&gt; all my aliases are shortcuts for git commands. The &lt;code&gt;lg&lt;/code&gt; alias is a shortcut for &lt;code&gt;git log&lt;/code&gt; with custom formatting. &lt;code&gt;lc&lt;/code&gt; is the same, but it only shows the last fetched commits. While you&#39;re adding aliases don&#39;t forget to alias git itself as well. I&#39;ve added the following to &lt;code&gt;~/.bash_login&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;git&#39;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Make the autocompleton work with the g alias&lt;/span&gt;
complete &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; bashdefault &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; default &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; nospace &lt;span class=&quot;token parameter variable&quot;&gt;-F&lt;/span&gt; _git g &lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt;/dev/null &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; complete &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; default &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; nospace &lt;span class=&quot;token parameter variable&quot;&gt;-F&lt;/span&gt; _git g&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Editor and difftool&lt;/h2&gt;
&lt;p&gt;I&#39;ve changed my default git editor to Textmate. This means commands that require text entry, such as commit and tag, will open Textmate. You can change the editor by running: &lt;code&gt;git config --global core.editor &#39;mate -w&#39;&lt;/code&gt; or by setting the &lt;code&gt;GIT_EDITOR&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;p&gt;Lastly I&#39;ve also changed my difftool to &lt;a href=&quot;http://www.kaleidoscopeapp.com&quot;&gt;Kaleidoscope&lt;/a&gt;. This is easily done from Kaleidscope itself by going to the Integration in the Kaleidscope menu. If you don&#39;t have Kaleidoscope already you can &lt;a href=&quot;http://www.approvalparty.com&quot;&gt;currently&lt;/a&gt; buy it for a 50% discount in the &lt;a href=&quot;http://itunes.apple.com/us/app/kaleidoscope/id412622418?mt=12&amp;amp;ls=1&quot;&gt;Mac app store&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;This is just a summary of how I configured git. If this post has whet your appetite use &lt;a href=&quot;http://www.google.com&quot;&gt;Google&lt;/a&gt; and mix and match several setups to find &lt;em&gt;your&lt;/em&gt; perfect git setup.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Announcing autonib2cib</title>
    <link href="https://annema.me/blog/archive/2011-03-05-announcing-autonib2cib/" />
    <updated>2011-03-05T19:20:00Z</updated>
    <id>https://annema.me/blog/archive/2011-03-05-announcing-autonib2cib/</id>
    <content type="html">&lt;p&gt;Some time ago I posted a &lt;a href=&quot;https://gist.github.com/799190&quot;&gt;gist&lt;/a&gt; for a command line utility that automatically nib2cibs changed nibs. During the weekend I&#39;ve rewritten the utility, making it more reliable with newly created nibs and nibs containing resources.&lt;/p&gt;
&lt;p&gt;I&#39;ve also moved the code (all 100 lines of it) from the gist to it&#39;s own &lt;a href=&quot;https://github.com/klaaspieter/autonib2cib&quot;&gt;github repo&lt;/a&gt;. If you have a feature request or find a bug, please &lt;a href=&quot;https://github.com/klaaspieter/autonib2cib/issues&quot;&gt;create an issue&lt;/a&gt; or even better, a &lt;a href=&quot;https://github.com/klaaspieter/autonib2cib/pull/new/master&quot;&gt;pull request&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Take a look at the &lt;a href=&quot;https://github.com/klaaspieter/autonib2cib#readme&quot;&gt;README&lt;/a&gt; for installation instructions. After installing you can start monitoring your nibs by running &lt;code&gt;autonib2cib &amp;lt;resource directory&amp;gt;&lt;/code&gt; in your terminal.&lt;/p&gt;
&lt;p&gt;Cappuccino has been very successful at preserving the customary &#39;code and refresh&#39; workflow for web developers. However, as any developer with more than a handful of cibs knows, having to manually run nib2cib breaks this workflow. Autonib2cib will solve this problem by automating the nib2cib process.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;autonib2cib &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;resource directory&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>Improving the Cappuccino Theme System</title>
    <link href="https://annema.me/blog/archive/2010-11-05-improving-the-cappuccino-theme-system/" />
    <updated>2010-11-05T20:13:00Z</updated>
    <id>https://annema.me/blog/archive/2010-11-05-improving-the-cappuccino-theme-system/</id>
    <content type="html">&lt;p&gt;I&#39;ve written about the Cappuccino theming system before[^1] and I have a confession to make, I don&#39;t like the current system.&lt;/p&gt;
&lt;p&gt;Let me clarify. Being able to change every visual aspect of a view is great, but  currently it&#39;s too complex.&lt;/p&gt;
&lt;p&gt;It&#39;s complex because a it requires manual building, even during development. I should be able to make a change, refresh the browser and see the difference. Just like developing everything else on the web, including Objective-J.&lt;/p&gt;
&lt;p&gt;Objective-J itself is also part of the complexity. &lt;code&gt;setValue:forThemeAttribute:inState&lt;/code&gt; works great for small amounts of theme changes. But it becomes unreadable when changing large parts of a theme.&lt;/p&gt;
&lt;p&gt;With all the talent in the Cappuccino community I&#39;m sure we can work around these problems with the current system. It will however not fix the biggest issue. Designers &lt;em&gt;won&#39;t&lt;/em&gt; theme as long as we&#39;re using Objective-J as our theming language.&lt;/p&gt;
&lt;p&gt;This is a huge step backwards. Designers have been able to style websites &lt;a href=&quot;http://en.wikipedia.org/wiki/Cascading_Style_Sheets#History&quot;&gt;for years&lt;/a&gt; using CSS. I don&#39;t see why that isn&#39;t possible for (Cappuccino) web applications.&lt;/p&gt;
&lt;p&gt;Now is the time for the skeptics to say that this impossible or to hard to do. Well, as we say in Dutch, &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Improving%20the%20Cappuccino%20Theme%20System/index-debug.html&quot;&gt;watch and shiver&lt;/a&gt;[^2].&lt;/p&gt;
&lt;p&gt;Obviously this application is a big hack, but it does show what is already possible. Imagine what we could do if we implemented this properly.&lt;/p&gt;
&lt;p&gt;In the application I use a Javascript CSS parser. This prevents the need for a separate build phase during development. When the application is ready to be deployed, the CSS can still be build into an optimized format. CSS is also a far more readable theming language and most designers already know and use it.&lt;/p&gt;
&lt;p&gt;Now to also get them to use Git.&lt;/p&gt;
&lt;p&gt;[^1]: Previous posts are &lt;a href=&quot;http://www.annema.me/blog/post/cappuccino-custom-themes&quot;&gt;Cappuccino Custom Themes&lt;/a&gt; and &lt;a href=&quot;http://www.annema.me/blog/post/the-basics-of-cappuccino-theming&quot;&gt;The Basics of Cappuccino Theming&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;[^2]: The source is available &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Improving%20the%20Cappuccino%20Theme%20System/Improving%20the%20Cappuccino%20Theme%20System.zip&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Cappuccino Custom Themes</title>
    <link href="https://annema.me/blog/archive/2010-09-16-cappuccino-custom-themes/" />
    <updated>2010-09-16T17:17:00Z</updated>
    <id>https://annema.me/blog/archive/2010-09-16-cappuccino-custom-themes/</id>
    <content type="html">&lt;p&gt;A while ago I wrote a blog post about &lt;a href=&quot;http://www.annema.me/blog/post/the-basics-of-cappuccino-theming&quot;&gt;the basics of Cappuccino theming&lt;/a&gt;. Since then I&#39;ve got a lot of questions about how to create fully customized themes.&lt;/p&gt;
&lt;p&gt;The first step in building your own custom theme is to create a theme descriptor. If you&#39;ve built Cappuccino &lt;a href=&quot;http://github.com/280north/cappuccino/wiki/Getting-and-Building-the-Source&quot;&gt;from source&lt;/a&gt; you can create one using the following command:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; data-language=&quot;Shell&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;capp gen &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; ThemeDescriptor &lt;span class=&quot;token parameter variable&quot;&gt;--build&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-F&lt;/span&gt; BlendKit &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Theme name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you haven&#39;t installed Cappuccino from source, you can &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Cappuccino%20Theming/ThemeDescriptor.zip&quot;&gt;download&lt;/a&gt; a default theme descriptor.&lt;/p&gt;
&lt;p&gt;You should now have a folder with the theme descriptor file, a resources directory and a Jakefile. A theme descriptor also includes a handy showcase application which you can use to preview your theme. Running the showcase is simply a matter of opening &lt;code&gt;index.html&lt;/code&gt; or &lt;code&gt;index-debug.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The showcase by default isn&#39;t very helpful, it only has an ugly button. If you open the theme descriptor you&#39;ll see the &lt;code&gt;+ (CPButton)themedButton&lt;/code&gt; class method. You can change the theme properties for a button by setting additional theme values in this method. How to change theme values is described in my previous &lt;a href=&quot;http://www.annema.me/blog/post/the-basics-of-cappuccino-theming&quot;&gt;blog post&lt;/a&gt; about Cappuccino theming.&lt;/p&gt;
&lt;p&gt;Unfortunately theme-able properties are not documented. You&#39;ll have to take a look at Aristo&#39;s theme descriptor or check the &lt;code&gt;+ (id)themeAttributes&lt;/code&gt; method of a class and all of it&#39;s superclasses.&lt;/p&gt;
&lt;p&gt;Theming another class is done by implementing another &lt;code&gt;+(&amp;lt;Class&amp;gt;)themed&amp;lt;Class&amp;gt;&lt;/code&gt; method. If the class is initialized with a frame and some theme values it will automatically show in the theme showcase. Take a look at &lt;a href=&quot;http://github.com/280north/cappuccino/blob/master/AppKit/Themes/Aristo/ThemeDescriptors.j&quot;&gt;Aristo&#39;s theme descriptor&lt;/a&gt; to see what you can do.&lt;/p&gt;
&lt;p&gt;The next step is building your theme. You can do this by running &lt;code&gt;jake debug&lt;/code&gt; or &lt;code&gt;jake install&lt;/code&gt; inside your theme directory. The build process will take the resources and theme descriptor and build it into a theme blend. After the build is done, the theme blend can be found in: &lt;code&gt;Build/[Configuration]/[Theme name].blend&amp;gt;&lt;/code&gt;. [Configuration] is either Debug or Release, depending on the jake argument used.&lt;/p&gt;
&lt;p&gt;The theme blend is what is needed to actually load the theme in your Cappuccino application. The easiest way to load the theme is by adding the following to your application&#39;s Info.plist:&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot; data-language=&quot;XML&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CPDefaultTheme&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;[Theme name]&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will automatically set the custom theme as the default theme for the application. This will override Aristo (Cappuccino&#39;s default theme) and set your theme as the default for the application.&lt;/p&gt;
&lt;p&gt;If you load your application, you&#39;ll see there&#39;s an error; Cappuccino can&#39;t find your theme blend. This is because Cappuccino will look inside your application bundle&#39;s resource directory for the theme blend and it was built somewhere else. The easiest way to solve this is to symlink the theme blend inside the Resources directory. This also makes sure any changes to your theme are automatically applied in your application when you rebuild the theme.&lt;/p&gt;
&lt;p&gt;As mentioned before the previously described method of loading a Theme will completely override Aristo. If you want to use Aristo in addition to your own theme you can load the theme blend manually. The following code shows how this is done:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;applicationDidFinishLaunching&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CPNotification&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;aNotification
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	var bundle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;CPBundle mainBundle&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	    blend &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;CPThemeBlend alloc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; initWithContentsOfURL&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
				 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;bundle pathForResource&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;&amp;lt;Theme name&gt;.blend&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;blend loadWithDelegate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;blendDidFinishLoading&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CPThemeBlend&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;theBlend
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// Show your application and use your custom theme&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When using this method it&#39;s advisable to show your application after the blend finished loading. This way you&#39;ll never have flashes when the custom theme loads.&lt;/p&gt;
&lt;p&gt;After the blend is loaded you can apply it to any view:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;var customTheme &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;CPTheme themeNamed&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Theme name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
     button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;CPButton buttonWithTitle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Custom themed button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;button setTheme&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;customTheme&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;ve wrapped up both methods of theming into separate projects. Both can be downloaded &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Cappuccino%20Theming/Cappuccino%20Custom%20Themes.zip&quot;&gt;here&lt;/a&gt;. Please let me know if you have any questions in the &lt;a href=&quot;https://annema.me/blog/archive/2010-09-16-cappuccino-custom-themes/#comment_form&quot;&gt;comments&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>NSConference MINI 2010 Sessions Online</title>
    <link href="https://annema.me/blog/archive/2010-07-22-nsconference-mini-2010-sessions-online/" />
    <updated>2010-07-22T15:46:00Z</updated>
    <id>https://annema.me/blog/archive/2010-07-22-nsconference-mini-2010-sessions-online/</id>
    <content type="html">&lt;p&gt;This year, European developers had a hard time attending the &lt;a href=&quot;http://developer.apple.com/wwdc&quot;&gt;WWDC&lt;/a&gt;, Apple&#39;s developers conference. The announcement was to late, forcing developers to arrange an entire inter continental trip in a relative short amount of time. There was also the pretty steep price and of course it was sold out within just 8 days!&lt;/p&gt;
&lt;p&gt;Luckily the community took care of us. The Mac Developer Network hosted a mini NSConference during WWDC. Wanting to help out, I gave a talk about the &lt;a href=&quot;http://cappuccino.org&quot;&gt;Cappuccino&lt;/a&gt; frameworks.&lt;/p&gt;
&lt;p&gt;My session and all the others given during NSConference MINI are now available at the &lt;a href=&quot;http://www.mac-developer-network.com/video/video101038.html&quot;&gt;Mac Developer Network&lt;/a&gt; website. You can get all of the sessions in one pack for 50 dollars[^1].&lt;/p&gt;
&lt;p&gt;[^1]: As far as I&#39;m aware there&#39;s no way to buy individual sessions, so if you&#39;re only interested in one talk you&#39;re still going to have to pay the full sum for all the sessions.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The future</title>
    <link href="https://annema.me/blog/archive/2010-07-19-the-future/" />
    <updated>2010-07-19T13:33:00Z</updated>
    <id>https://annema.me/blog/archive/2010-07-19-the-future/</id>
    <content type="html">&lt;p&gt;Most of you probably already know, but for those who don’t; the company I work at, &lt;a href=&quot;http://www.madebysofa.com&quot;&gt;Sofa&lt;/a&gt; was acquired by &lt;a href=&quot;http://www.madebysofa.com/blog/facebook-acquires-sofa/&quot;&gt;Facebook&lt;/a&gt;. For reasons I can’t disclose I was not part of the acquisition.&lt;/p&gt;
&lt;p&gt;The last couple of weeks have been a very emotional and busy period. Over the course of two weeks I went from having a job I enjoyed, to moving to the Bay Area for a job at Facebook, to having no job at all. In other words my future was destroyed, recreated and destroyed again.&lt;/p&gt;
&lt;p&gt;Even though Facebook wasn’t an option, I didn’t want to waste the opportunity to move to the US. I got a ton of job offers during WWDC and I spend most of my time pursuing them trying to find a job in San Francisco.&lt;/p&gt;
&lt;p&gt;While I was interviewing at another company I got an email from Sofa’s partner in &lt;a href=&quot;http://www.checkoutapp.com&quot;&gt;Checkout&lt;/a&gt;, &lt;a href=&quot;http://acclivitysoftware.com&quot;&gt;Acclivity&lt;/a&gt;. They wanted me to stop by New Jersey on my way back home to talk about my future and offered me an opportunity to continue development on &lt;a href=&quot;http://www.enstore.com&quot;&gt;Enstore&lt;/a&gt; and Checkout. Although I had set my mind on San Francisco this was an opportunity too good to pass by.&lt;/p&gt;
&lt;p&gt;I’ll be part of a newly formed NYC based company responsible for Enstore and Checkout. My wife and I will be moving to New York City as soon as my visa is arranged. Suggestions where to live, eat and spend our spare time are very welcome.&lt;/p&gt;
&lt;p&gt;In closing I would like to thank all the companies that offered me a job and all the great people that helped me out trying to find a new job! The last couple of months have been a hard and emotional period, but I’m sure the future will make up for it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Programmatically Scroll a UIWebView</title>
    <link href="https://annema.me/blog/archive/2010-05-15-programmatically-scroll-a-uiwebview/" />
    <updated>2010-05-15T04:33:00Z</updated>
    <id>https://annema.me/blog/archive/2010-05-15-programmatically-scroll-a-uiwebview/</id>
    <content type="html">&lt;p&gt;Ever wanted to scroll a UIWebView programmatically on the iPad or iPhone? Unfortunately Apple doesn&#39;t have a public API to do this, but there is a way. A UIWebView can execute any arbitrary javascript with &lt;code&gt;stringByEvaluatingJavaScriptFromString:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Using this method we can easily scroll a web view like so:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;webView stringByEvaluatingJavaScriptFromString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;window.scrollTo(0.0, 100.0)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s also possible to save the scroll state of the web view through javascript:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;CGFloat xOffset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; webView&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; stringByEvaluatingJavaScriptFromString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;pageXOffset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; floatValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
CGFloat yOffset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;self&lt;/span&gt; webView&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; stringByEvaluatingJavaScriptFromString&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;pageYOffset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; floatValue&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;ve used and tested both of these methods and haven&#39;t found any bugs or weird issues. I&#39;ve filed radar bug 8184256: No API for programmatically scrolling / zooming a UIWebView. It has been marked as a duplicate of radar bug 5912563.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The Basics of Cappuccino Theming</title>
    <link href="https://annema.me/blog/archive/2010-04-06-the-basics-of-cappuccino-theming/" />
    <updated>2010-04-06T06:02:00Z</updated>
    <id>https://annema.me/blog/archive/2010-04-06-the-basics-of-cappuccino-theming/</id>
    <content type="html">&lt;p&gt;This is the second post of a series of posts about Cappuccino where I explain the subjects I talked about during my &lt;a href=&quot;http://www.cocoaheads.nl&quot;&gt;CocoaHeads Amsterdam&lt;/a&gt; presentation. The first post can be found &lt;a href=&quot;http://www.annema.me/blog/post/objective-j-explained-brtoll-free-bridges&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cappuccino and Cocoa have a lot of similarities, but there are some differences. Most prominent is probably Cappuccino&#39;s theming engine. Web developers are accustomed to a certain level of customization that Cocoa does not provide. The theming engine provides this freedom to Cappuccino developers.&lt;/p&gt;
&lt;p&gt;The theming engine let&#39;s you customize any theme-able attribute of CPView. Every subclass of CPView can declare it&#39;s own theme-able attributes by implementing the &lt;code&gt;themeAttributes&lt;/code&gt; class method and returning a CPDictionary with the attribute names as keys and their default value as values.&lt;/p&gt;
&lt;h2&gt;Theme states&lt;/h2&gt;
&lt;p&gt;Before going into theming you&#39;ll have to know something about theme states. Basically every Cappuccino view has a theme state. The current theme state can be found by calling the &lt;code&gt;themeState&lt;/code&gt; method on any view.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;themeState&lt;/code&gt; method itself is not extremely useful since you&#39;ll only get a unsigned integer back, it&#39;s up to you to find the actual theme state. Far more useful is the &lt;code&gt;currentValueForThemeAttribute:&lt;/code&gt; method. This methods takes a string, the name of the theme-attribute, and returns it&#39;s current value.&lt;/p&gt;
&lt;p&gt;Changing theme states is done through the &lt;code&gt;setThemeState:&lt;/code&gt; and &lt;code&gt;unsetThemeState:&lt;/code&gt; method. They both take a string with the state name or the CPThemeState itself as their only argument.&lt;/p&gt;
&lt;h2&gt;Changing theme-attributes&lt;/h2&gt;
&lt;p&gt;Most (if not all) of the state changing is handled by Cappuccino. Unless you are creating a custom control, you won&#39;t need to touch any of the the above methods. Far more important is the &lt;code&gt;setValue:forThemeAttribute:inState:&lt;/code&gt; method. Let&#39;s take a look at changing the left and right content inset of a CPButton:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;button setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CGInsetMake&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; forThemeAttribute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;content-inset&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we don&#39;t want the text to jump around when changing states we don&#39;t explicitly name the state, this effectively sets a fallback value. When a control is in a state with no defined value, the control will fall back to using this value.&lt;/p&gt;
&lt;p&gt;Let&#39;s also take a look at setting theme-attributes for different states:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;button setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;buttonBezel forThemeAttribute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;bezel-color&quot;&lt;/span&gt; inState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;CPThemeStateBordered&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;button setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;highlightedButtonBezel forThemeAttribute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;bezel-color&quot;&lt;/span&gt; inState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;CPThemeStateBordered &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; CPThemeStateHighlighted&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;button setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;disabledButtonBezel forThemeAttribute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;bezel-color&quot;&lt;/span&gt; inState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;CPThemeStateBordered &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; CPThemeStateDisabled&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assuming the bezel colors are defined, the above sets the bezel color for the normal, highlighted and disabled state.&lt;/p&gt;
&lt;p&gt;During my presentation I used an example of a large button to show how the theming engine works. All the code used in this post came from that example. The project can be downloaded &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Cappuccino%20Theming/Theming%20Cappuccino%20-%20The%20Basics.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are the basics of the theming engine. In my own code I often use:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;forThemeAttribute&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;inState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to quickly change small details&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://annema.me/blog/archive/2010-04-06-the-basics-of-cappuccino-theming/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. I don&#39;t recommend creating your own, fully custom, themes this way. It will only result in a lot of clutter in your code. If you want to create your own theme, you should take a look at theme descriptors&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://annema.me/blog/archive/2010-04-06-the-basics-of-cappuccino-theming/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The last thing I talked about during my CocoaHeads presentation is data availability. Cappuccino and Cocoa both assume data to be available when the application launches. I&#39;ll discuss this problem in more detail in the next, and last, post of the series.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Like issues with text in a control with odd height, resulting in the text appearing a pixel off center. &lt;a href=&quot;https://annema.me/blog/archive/2010-04-06-the-basics-of-cappuccino-theming/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I tried to find a good post about theme descriptors to link to, but unfortunately I couldn&#39;t find one. If you know of one, I&#39;d be happy to link to it. &lt;a href=&quot;https://annema.me/blog/archive/2010-04-06-the-basics-of-cappuccino-theming/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Objective-J Explained: Toll-Free Bridges</title>
    <link href="https://annema.me/blog/archive/2010-03-19-objective-j-explained-toll-free-bridges/" />
    <updated>2010-03-19T21:34:00Z</updated>
    <id>https://annema.me/blog/archive/2010-03-19-objective-j-explained-toll-free-bridges/</id>
    <content type="html">&lt;p&gt;Last week I gave a talk on the &lt;a href=&quot;http://www.cappuccino.org&quot;&gt;Cappuccino&lt;/a&gt; frameworks during a &lt;a href=&quot;http://www.cocoaheads.nl&quot;&gt;Cocoaheads Amsterdam&lt;/a&gt; meeting. This post is the first in a series in which I&#39;ll explain several of the subjects I talked about during my presentation. I didn&#39;t have a lot of slides and they won&#39;t make much sense without explanation but for those that are interested you can download them &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Objective-J%20Explained/Cocoaheads%20Cappuccino.key&quot;&gt;here&lt;/a&gt;. All of the examples used in this post can be downloaded &lt;a href=&quot;http://dl.dropbox.com/u/3415875/Blog/Objective-J%20Explained/Objective-J-Explained.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m going to start of this series at the basis of the Cappuccino framework, Javascript. In the end Cappuccino and Objective-J are build on top of this one language and that allows for some pretty cool things. Cool things which will look familiar to Cocoa developers and cool things that can make the transition for Javascript developers easier.&lt;/p&gt;
&lt;p&gt;The following code shows an example:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 1 Declare a javascript array&lt;/span&gt;
var array &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
CPLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Step 1: %@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 2 Call an Objective-J method on it&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array addObject&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;first object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
CPLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Step 2: %@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; first object&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 3 Call a Javascript function&lt;/span&gt;
array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;SECOND OBJECT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
CPLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Step 3: %@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; first object,SECOND OBJECT&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 4 Mix it up&lt;/span&gt;
array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array objectAtIndex&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
CPLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Step 4: %@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array objectAtIndex&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; true&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 5 Do something wacky&lt;/span&gt;
array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array indexOfObject&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;SECOND OBJECT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array objectAtIndex&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array indexOfObject&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;SECOND OBJECT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
CPLog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;Step 5: %@&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; first object,second object&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of the above code is perfectly valid. This is an example of a toll-free bridge. A toll-free bridged object is both an instance of a regular Javascript and an instance of an Objective-J object. In Objective-J CPArray and CPString are toll-free bridged to their Javascript equivalents.&lt;/p&gt;
&lt;p&gt;As you see you can mix and match both syntaxes as you feel fit. &lt;strong&gt;A word of caution&lt;/strong&gt;. The above example (especially step 5) is contrived, I do not recommend mixing syntax like this in production code since it can make your code very hard to read and maintain. Personally I only use Javascript literal array notation to create arrays because it&#39;s shorter and more readable than &lt;code&gt;[CPArray array]&lt;/code&gt;. I also use regular Javascript objects in stead of CPDictionaries because CPDictionary is &lt;em&gt;not&lt;/em&gt; toll-free bridged with the Javascript object.&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 1. Create a regular javascript object using literal notation&lt;/span&gt;
var object &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; {}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 2. Add a key value pair to it using javascript&lt;/span&gt;
object&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&#39;key1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&#39;value1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; {&quot;key1&quot;: &quot;value1&quot;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 3. Attempt to add another key value pair using Objective-J&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;object setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;value2&quot;&lt;/span&gt; forKey&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;key2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; TypeError: Result of expression &#39;isa&#39; [undefined] is not an object.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you prefer using CPDictionaries over Javascript objects you can transform it into a CPDictionary like so:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 1. Create the object from the previous example&lt;/span&gt;
var object &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;key1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;value1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; {&quot;key1&quot;: &quot;value1&quot;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 2. Make a CPDictionary out of it&lt;/span&gt;
var dictionary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;CPDictionary dictionaryWithJSObject&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;object recursively&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; {&quot;key1&quot;: &quot;value1&quot;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 3. Attempt to add the key value pair using Objective-J again&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;dictionary setValue&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;value2&quot;&lt;/span&gt; forKey&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;key2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &gt; {&quot;key1&quot;: &quot;value1&quot;, &quot;key2&quot;: &quot;value2&quot;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I personally never do this because, to me:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;key1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;value1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;key2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&quot;value2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;is far more readable than:&lt;/p&gt;
&lt;pre class=&quot;language-objc&quot; data-language=&quot;Objective-C&quot;&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;CPDictionary dictionaryWithObjectsAndKeys&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;@&quot;value1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;key1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;value2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;@&quot;key2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you&#39;ve seen, Objective-J and Javascript differ in syntax a lot, but are still very much the same thing.&lt;/p&gt;
&lt;p&gt;As I&#39;ve said earlier, this post is the start of a series of posts about Cappuccino. The next one will be about Theming, make sure you don&#39;t miss it by &lt;a href=&quot;feed://feeds.feedburner.com/annemame&quot;&gt;subscribing&lt;/a&gt; to my feed or &lt;a href=&quot;http://www.twitter.com/klaaspieter/&quot;&gt;following&lt;/a&gt; me on Twitter.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Welcome!</title>
    <link href="https://annema.me/blog/archive/2010-03-08-welcome/" />
    <updated>2010-03-08T19:27:00Z</updated>
    <id>https://annema.me/blog/archive/2010-03-08-welcome/</id>
    <content type="html">&lt;p&gt;After some delay it&#39;s finally here. Welcome to my blog! I intend to post here whenever I learn something new and interesting. I don&#39;t have a specific subject in mind, but it will certainly have to do with usability, design and software.&lt;/p&gt;
&lt;p&gt;The reason for me to start this blog is that I like talking about things I learn. Of course it&#39;s also kind of mandatory to have a blog nowadays.&lt;/p&gt;
&lt;p&gt;I intend to talk about the things I&#39;m currently working on, provided I &lt;em&gt;can&lt;/em&gt; talk about them. For now, this post will have to do. Thanks for stopping by and I hope to &lt;a href=&quot;feed://feeds.feedburner.com/annemame&quot;&gt;see you again&lt;/a&gt; soon!&lt;/p&gt;
</content>
  </entry>
</feed>