<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Scott Berrevoets - iOS Development</title><link href="https://scottberrevoets.com/" rel="alternate"/><link href="https://scottberrevoets.com/feeds/ios-development.atom.xml" rel="self"/><id>https://scottberrevoets.com/</id><updated>2025-09-19T00:00:00-07:00</updated><entry><title>Localization troubles with Swift PM</title><link href="https://scottberrevoets.com/2025/09/19/localization-troubles-with-swift-pm/" rel="alternate"/><published>2025-09-19T00:00:00-07:00</published><updated>2025-09-19T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2025-09-19:/2025/09/19/localization-troubles-with-swift-pm/</id><summary type="html">&lt;p&gt;A few weeks ago we got bit by a piece of Apple magic in its localization
workflow when combined with Swift PM. The problem we ran into was that as soon
as we moved all our &lt;code&gt;Localizable.strings&lt;/code&gt; files to an SPM package, none of the
localizations would be picked …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few weeks ago we got bit by a piece of Apple magic in its localization
workflow when combined with Swift PM. The problem we ran into was that as soon
as we moved all our &lt;code&gt;Localizable.strings&lt;/code&gt; files to an SPM package, none of the
localizations would be picked up anymore and the app would display in
English&amp;mdash;but &lt;strong&gt;only for first-time installations&lt;/strong&gt;. We followed the
documentation guidelines for how to localize an app in an Swift PM environment
and have no custom tooling in place, so it was a bit of a headscratcher.&lt;/p&gt;
&lt;p&gt;The modern way of adding support for another language/region in Xcode is through
the project's &lt;em&gt;Info&lt;/em&gt; tab. Simply click the + and add a language and the app now
supports localizing in that language.&lt;/p&gt;
&lt;p&gt;Adding localizations for any resource is done by clicking the &lt;em&gt;Localize...&lt;/em&gt;
button in the Attributes inspector. After confirming the language, Xcode creates
a new &lt;code&gt;.lproj&lt;/code&gt; folder for the selected language and moves the resource into that
folder. The end result is the project will have a &lt;code&gt;.lproj&lt;/code&gt; folder for each
localization as well as the &lt;code&gt;Base.lproj&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;just works&lt;/em&gt;. The &lt;code&gt;.lproj&lt;/code&gt; folders get copied over to the &lt;code&gt;.app&lt;/code&gt; and at
runtime the SDK knows how to read and use these folders. Xcode also gives visual
confirmation in the &lt;em&gt;Info&lt;/em&gt; tab by indicating for how many files it has picked up
a localized version per language/region.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Xcode sees three localized files" src="/images/xcode-localizations-3.png"&gt;&lt;/p&gt;
&lt;p&gt;Getting started with adding some SPM packages in our app, we moved the &lt;code&gt;.lproj&lt;/code&gt;
folders into our &lt;code&gt;Localization&lt;/code&gt; package at
&lt;code&gt;Localization/Sources/Localization/Resources/&lt;/code&gt;, which follows the process
outlined in the &lt;a href="https://developer.apple.com/documentation/xcode/localizing-package-resources"&gt;documentation&lt;/a&gt;. Locally this seemed to work and we shipped the
change, only for QA to report localizations were broken throughout the app.&lt;/p&gt;
&lt;p&gt;As it turns out, any &lt;code&gt;.lproj&lt;/code&gt; folders in &lt;strong&gt;SPM packages&lt;/strong&gt; aren't considered when
determining what localizations are available. At first this was a bit confusing,
but it makes sense for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Through various layers of abstraction, the system looks up the available
   localizations using methods on &lt;code&gt;Bundle&lt;/code&gt;. &lt;code&gt;Bundle.localizations&lt;/code&gt; simply finds
   all &lt;code&gt;.lproj&lt;/code&gt; folders in that bundle. SPM package bundles aren't included in
   &lt;code&gt;Bundle.main&lt;/code&gt;, which is the bundle that's used to determine app-wide
   localizations.&lt;/li&gt;
&lt;li&gt;An SPM package can be localized in different languages than the app that
   integrates the package, especially if the package is from an external vendor.
   It could be weird behavior to have the app's selected localization be
   determined by some SPM package.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;There is an Info.plist key that would allow SPM packages to use a different
localization than the main app: &lt;code&gt;CFBundleAllowMixedLocalizations&lt;/code&gt;.
I haven't tried for myself, but setting this to &lt;code&gt;YES&lt;/code&gt; allows different
localizations for the app and for every package.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;When moving all &lt;code&gt;.lproj&lt;/code&gt; folders into the SPM package, the app didn't have any
localized files left and Xcode indicated as much. &lt;/p&gt;
&lt;p&gt;&lt;img alt="Xcode sees no localized files" src="/images/xcode-localizations-0.png"&gt;&lt;/p&gt;
&lt;p&gt;As a result, the app would always default to English. This explained why things
were broken but there were still a few questions left.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How come the correct localization was used for returning users?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This issue only happened to users that freshly installed the app. Upon first
launch, we store the user's locale in &lt;code&gt;UserDefaults&lt;/code&gt; (later giving users the
ability to override this manually). Instead of reading strings from
&lt;code&gt;Bundle.main&lt;/code&gt; we read them from a new &lt;code&gt;Bundle&lt;/code&gt; instance specifically scoped to
that locale:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;defaultLocale&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preferredLocalizations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;userLanguage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="c1"&gt;// e.g. &amp;quot;nl&amp;quot; for Dutch&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pathForResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="n"&gt;defaultLocale&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;lproj&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;customBundle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;localized&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;This setup has some interesting results:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ &lt;code&gt;Bundle.main.preferredLocalizations&lt;/code&gt; only contains the development default
  locale &lt;code&gt;en&lt;/code&gt; as the main bundle doesn't have any localizations&lt;/li&gt;
&lt;li&gt;❌ &lt;code&gt;customBundle.preferredLocalizations&lt;/code&gt; only contains the localization it was
  scoped to&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;customBundle.localizedString(forKey:value:table:)&lt;/code&gt; works as the SPM
  package's resources still get copied into the main app as a separate bundle&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;Bundle.module.preferredLocalizations&lt;/code&gt; correctly returns all the supported
  localizations since they're defined in the SPM package&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;Bundle.module.localizedString(forKey:value:table:)&lt;/code&gt; works for the same
  reason&lt;/li&gt;
&lt;li&gt;❌ &lt;code&gt;Bundle.main.localizedString(forKey:value:table:)&lt;/code&gt; does not work as the
  main bundle doesn't have any localizations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For first-time users we would read &lt;code&gt;en&lt;/code&gt; as their preferred language through
&lt;code&gt;Bundle.main.preferredLocalizations&lt;/code&gt;, but for returning users we'd read what
language they were using before from &lt;code&gt;UserDefaults&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Conclusion: we should be using &lt;code&gt;Bundle.module.preferredLocalizations&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why was it so difficult to figure this out?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The build cache in Xcode messed with our ability to reproduce the issue. In
understanding what commit introduced the problem, we would often switch branches
but that didn't invalidate the build cache.&lt;/p&gt;
&lt;p&gt;So building any commit before the offending change would copy the &lt;code&gt;.lproj&lt;/code&gt;
folders into the main app's build cache, and those folders would stay there
after checking out and building the offending commit.&lt;/p&gt;
&lt;p&gt;At first we thought the issue was only intermittently reproducible, but once we
realized the build cache was "polluted" we started to clean it every time. This
made it much easier to reproduce but much slower to test due to constantly doing
full builds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What am I supposed to do in a fully modularized app where there are no files
to localize in the main app?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In theory, using &lt;code&gt;Bundle.module&lt;/code&gt; everywhere would work as highlighted above.
However, that's pretty cumbersome and there's a nicer way:
&lt;code&gt;CFBundleLocalizations&lt;/code&gt;. This is another &lt;a href="https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundlelocalizations"&gt;Info.plist key&lt;/a&gt; that lets you
&lt;em&gt;explicitly&lt;/em&gt; define what localizations the app handles, instead of looking for
&lt;code&gt;.lproj&lt;/code&gt; folders and implicitly supporting the localizations for the folders
Xcode finds. With that key set, Xcode still does look for these folders but now
it also considers SPM bundles, fixing the issue.&lt;/p&gt;
&lt;p&gt;Finally, there's another way to be explicit about the localizations a project
supports: by adding a localization through Xcode's &lt;em&gt;Info&lt;/em&gt; tab. This sets the
&lt;code&gt;knownRegions&lt;/code&gt; value in the Xcode project file, which is not only considered for
determining what localizations to consider at build time, but is also used to
export and import &lt;code&gt;xliff&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;That would have fixed our issue as well, but I personally prefer to not touch
the project file as much as possible and be explicit about what localizations
are supported through &lt;code&gt;CFBundleLocalizations&lt;/code&gt;.&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/></entry><entry><title>Re-binding self: the debugger's break(ing) point</title><link href="https://scottberrevoets.com/2018/08/08/re-binding-self-the-debuggers-breaking-point/" rel="alternate"/><published>2018-08-08T00:00:00-07:00</published><updated>2018-08-08T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2018-08-08:/2018/08/08/re-binding-self-the-debuggers-breaking-point/</id><summary type="html">&lt;p&gt;&lt;strong&gt;Update 07-29-2019: The bug described below is fixed in Xcode 11 so this blog
post has become irrelevant. I'm leaving it up for historical purposes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the Objective-C veterans in the audience, the strong-self-weak-self dance is
a practice mastered early on and one that is used very frequently. There are …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Update 07-29-2019: The bug described below is fixed in Xcode 11 so this blog
post has become irrelevant. I'm leaving it up for historical purposes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the Objective-C veterans in the audience, the strong-self-weak-self dance is
a practice mastered early on and one that is used very frequently. There are a
lot of different incantations, but the most basic one goes something like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;__weak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weakSelf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dispatch_group_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dispatch_get_main_queue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;weakSelf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Then, if you needed a strong reference to &lt;code&gt;self&lt;/code&gt; again inside the block, you'd
change it to this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;__weak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weakSelf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dispatch_group_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dispatch_get_main_queue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weakSelf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strongSelf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;weakSelf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;strongSelf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;someOtherObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doSomethingWith&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;strongSelf&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Fortunately, this was much easier on day 1 of Swift when using the &lt;code&gt;[weak self]&lt;/code&gt;
directive:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;weak&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;strongSelf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;strongSelf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;someOtherObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;strongSelf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;&lt;code&gt;self&lt;/code&gt; is now &lt;code&gt;weak&lt;/code&gt; inside the closure, making it an optional. Unwrapping it
into &lt;code&gt;strongSelf&lt;/code&gt; makes it a non-optional while still avoiding a retain cycle.
It doesn't feel very Swifty, but it's not terrible.&lt;/p&gt;
&lt;p&gt;More recently, it's become known that Swift supports re-binding &lt;code&gt;self&lt;/code&gt; if you
wrap it in backticks. That makes for an arguably much nicer syntax:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;weak&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;someOtherObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;This was long considered, and &lt;a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160118/007425.html"&gt;confirmed&lt;/a&gt; to be, a hack that worked due to a bug in the compiler, but
since it worked and there weren't plans to remove it, people (including us at
Lyft) started treating it as a feature.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;However, there is one big caveat&lt;/strong&gt;: the debugger is entirely hosed for
anything you do in that closure. Ever seen an error like this in your Xcode
console?&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary aria-label="Toggle code block"&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;error: warning: &amp;lt;EXPR&amp;gt;:12:9: warning: initialization of variable &amp;#39;$__lldb_error_result&amp;#39; was never used; consider replacing with assignment to &amp;#39;_&amp;#39; or removing it
    var $__lldb_error_result = __lldb_tmp_error
        ~~~~^~~~~~~~~~~~~~~~~~~~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;That's because &lt;code&gt;self&lt;/code&gt; was re-bound. This is easy to reproduce: create a new
Xcode project and add the following snippet to &lt;code&gt;viewDidLoad()&lt;/code&gt;:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;DispatchQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;weak&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;
    &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// set a breakpoint here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;When the breakpoint hits, execute &lt;code&gt;(lldb) po description&lt;/code&gt; and you'll see the
error from above. Note that you're not even &lt;em&gt;using&lt;/em&gt; &lt;code&gt;self&lt;/code&gt; - merely re-binding
it makes the debugger entirely useless inside that scope.&lt;/p&gt;
&lt;p&gt;People with way more knowledge of LLDB than I do can explain this in more detail
(and &lt;a href="https://bugs.swift.org/browse/SR-6156"&gt;have&lt;/a&gt;), but the gist is that the
debugger doesn't like &lt;code&gt;self&lt;/code&gt;'s type changing. At the beginning of the closure
scope, the debugging context assumes that &lt;code&gt;self&lt;/code&gt;'s type is &lt;code&gt;Optional&lt;/code&gt;, but it is
then re-bound to a non-optional, which the debugger doesn't know how to handle.
It's actually pretty surprising the compiler supports changing a variable's type
at all.&lt;/p&gt;
&lt;p&gt;Because of this problem, at Lyft we have decided to eliminate this pattern
entirely in our codebases, and instead re-bind &lt;code&gt;self&lt;/code&gt; to a variable named
&lt;code&gt;this&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you do continue to use this pattern, note that in a
&lt;a href="https://forums.swift.org/t/the-future-of-weak-self-rebinding/10846"&gt;discussion&lt;/a&gt;
on the Swift forums many people agreed that re-binding &lt;code&gt;self&lt;/code&gt; should be
supported by the language without the need for backticks. The &lt;a href="https://github.com/apple/swift/pull/15306"&gt;pull
request&lt;/a&gt; was merged shortly after and
with the release of Swift 4.2 in the fall, you'll be able to use &lt;code&gt;guard let self
= self else { return }&lt;/code&gt; (at the cost of losing debugging capabilities!)&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/><category term="Developer Experience"/></entry><entry><title>Using Interface Builder at Lyft</title><link href="https://scottberrevoets.com/2017/03/06/using-interface-builder-at-lyft/" rel="alternate"/><published>2017-03-06T00:00:00-08:00</published><updated>2017-03-06T00:00:00-08:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2017-03-06:/2017/03/06/using-interface-builder-at-lyft/</id><summary type="html">&lt;p&gt;Last week people realized that Xcode 8.3 by default uses storyboards in new
projects without a checkbox to turn this off. This of course sparked the
Interface Builder vs. programmatic UI discussion again, so I wanted to give some
insight in our experience using Interface Builder in building the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last week people realized that Xcode 8.3 by default uses storyboards in new
projects without a checkbox to turn this off. This of course sparked the
Interface Builder vs. programmatic UI discussion again, so I wanted to give some
insight in our experience using Interface Builder in building the Lyft app. This
is not intended as hard "you should also use Interface Builder" advice, but
rather to show that IB &lt;em&gt;can&lt;/em&gt; work at a larger scale.&lt;/p&gt;
&lt;p&gt;First, some stats about the Lyft app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;40 storyboards&lt;/li&gt;
&lt;li&gt;100 XIB files&lt;/li&gt;
&lt;li&gt;150 view controllers&lt;/li&gt;
&lt;li&gt;20 people on the iOS team with occasional outside contributors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the
&lt;a href="https://www.skilled.io/u/keithsmiley/tales-of-a-rewrite-at-lyft"&gt;rewrite&lt;/a&gt; of
our app we moved to using IB for about 95% of our UI.&lt;/p&gt;
&lt;p&gt;The #1 complaint about using Interface Builder for a project with more than 1
developer is that it's impossible to resolve merge conflicts. &lt;strong&gt;We never have
this problem.&lt;/strong&gt; Everybody on the team can attest that they have never run into
major conflicts they couldn't reasonably resolve.&lt;/p&gt;
&lt;p&gt;With that concern out of the way, what about some of the other common criticisms
Interface Builder regularly gets?&lt;/p&gt;
&lt;h2 id="improving-the-workflow"&gt;Improving the workflow&lt;/h2&gt;
&lt;p&gt;Out of the box, IB has a number of shortcomings that could make working with it
more painful than it needs to be. For example, referencing IB objects from code
still can only be done with string identifiers. There is also no easy way to
embed custom views (designed in IB) in other custom views.&lt;/p&gt;
&lt;p&gt;Over time we have improved the workflow for our developers to mitigate some of
these shortcomings, either by writing some tools or by writing a little bit of
code that can be used project-wide.&lt;/p&gt;
&lt;h3 id="storyboarder-script"&gt;storyboarder script&lt;/h3&gt;
&lt;p&gt;To solve the issue of stringly-typed view controller identifiers, we wrote a
script that, just before compiling the app, generates a struct with static
properties that exposes all view controllers from the app in a strongly-typed
manner. This means that now we can instantiate a view controller in code like
this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;viewController&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Onboarding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignUp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Not only is &lt;code&gt;viewController&lt;/code&gt; now guaranteed to be there at runtime (if something
is wrong in the setup of IB the code won't even compile), but it's also
recognized as a &lt;code&gt;SignUpViewController&lt;/code&gt; and not a generic &lt;code&gt;UIViewController&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="strongly-typed-segues"&gt;Strongly-typed segues&lt;/h3&gt;
&lt;p&gt;All our view controllers have a base view controller named &lt;code&gt;ViewController&lt;/code&gt;.
This base controller implements &lt;code&gt;prepare(for:sender:)&lt;/code&gt; like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="kr"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;segue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;UIStoryboardSegue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;identifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;segue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;segueName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firstLetterUpperString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;selector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prepareFor&lt;/span&gt;&lt;span class="si"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;segueName&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s"&gt;:sender:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;segue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;This means that a view controller that has a segue to
&lt;code&gt;TermsOfServiceViewController&lt;/code&gt; can now do this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;@objc&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;prepareForTermsOfService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;viewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TermsOfServiceViewController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;viewController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onTermsAccepted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;weak&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;proceed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;We no longer have to implement &lt;code&gt;prepareForSegue&lt;/code&gt; and then &lt;code&gt;switch&lt;/code&gt; on the
segue's identifier or destination controller, but we can implement a separate
method for every segue from this view controller instead which makes the code
much more readable.&lt;/p&gt;
&lt;h3 id="nibview"&gt;&lt;code&gt;NibView&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We wrote a &lt;code&gt;NibView&lt;/code&gt; class to make it more convenient to embed custom views in
other views from IB. We marked this class with &lt;code&gt;@IBDesignable&lt;/code&gt; so that it knows
to render itself in IB. All we have to do is drag out a regular &lt;code&gt;UIView&lt;/code&gt; from
the object library and change its class. If there is a XIB with the same name as
the class, &lt;code&gt;NibView&lt;/code&gt; will automatically instantiate it and render it in the
canvas at design time and on screen at runtime.&lt;/p&gt;
&lt;p&gt;Every standalone view we design in IB (which effectively means every view in our
app) inherits from &lt;code&gt;NibView&lt;/code&gt; so we can have an "unlimited" number of nested
views show up and see the final result.&lt;/p&gt;
&lt;h3 id="basic-ibdesignables"&gt;Basic &lt;code&gt;@IBDesignable&lt;/code&gt;s&lt;/h3&gt;
&lt;p&gt;Since a lot of our views have corner radii and borders, we have created this
&lt;code&gt;UIView&lt;/code&gt; extension:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="bp"&gt;UIView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kr"&gt;@IBInspectable&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cornerRadius&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kr"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cornerRadius&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;@IBInspectable&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;borderWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borderWidth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kr"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borderWidth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kr"&gt;@IBInspectable&lt;/span&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;borderColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;UIColor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cgColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borderColor&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kr"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borderColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cgColor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;This lets us easily set these properties on &lt;em&gt;any&lt;/em&gt; view (including the ones from
UIKit) from Interface Builder.&lt;/p&gt;
&lt;h3 id="linter"&gt;Linter&lt;/h3&gt;
&lt;p&gt;We wrote a linter to make sure views are not misplaced, have
accessibility labels, trait variations are disabled (since we only officially
support portrait mode on iPhone), etc.&lt;/p&gt;
&lt;h3 id="ibunfuck"&gt;ibunfuck&lt;/h3&gt;
&lt;p&gt;A &lt;a href="https://forums.developer.apple.com/thread/8116"&gt;bug&lt;/a&gt; impacting developers
that use Interface Builder on both Retina and non-Retina screens (which at Lyft
is every developer) has caused us enough grief to write
&lt;a href="https://github.com/Reflejo/ib-unfuck-git"&gt;&lt;code&gt;ibunfuck&lt;/code&gt;&lt;/a&gt; - a tool to remove
unwanted changes from IB files.&lt;/p&gt;
&lt;h3 id="color-palette"&gt;Color palette&lt;/h3&gt;
&lt;p&gt;We created a custom color palette with the commonly used colors in our app so
it's easy to select these colors when building a new UI. The color names in the
palette follow the same names designers use when they give us new designs, so
it's easy to refer to and use without having to copy RGB or hex values.&lt;/p&gt;
&lt;h2 id="our-approach"&gt;Our approach&lt;/h2&gt;
&lt;p&gt;In addition to these tools and project-level improvements, we have a number of
"rules" around our use of IB to keep things sane:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do as little as possible in code, do as much as possible in IB. That means
  fonts, colors, images, and other properties should not be set in code if they
  don't change at runtime.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;@IBInspectable&lt;/code&gt; on custom views whenever possible.&lt;/li&gt;
&lt;li&gt;Create as much Auto Layout constraints in IB as possible. Sometimes this means
  being clever with how we create constraints so that at runtime we need very
  little code to manipulate a layout.&lt;/li&gt;
&lt;li&gt;If we do need to create constraints in code, we don't use the
  &lt;code&gt;NSLayoutConstraint&lt;/code&gt; (or &lt;code&gt;NSLayoutAnchor&lt;/code&gt;) methods directly. Instead we use
  &lt;a href="https://github.com/SnapKit/SnapKit"&gt;SnapKit&lt;/a&gt;'s convenience methods.&lt;/li&gt;
&lt;li&gt;We still manually push and present view controllers where possible. Even
  though we have created some niceties around using segues, it's still easy to
  accidentally remove one and not find out about it until runtime.&lt;/li&gt;
&lt;li&gt;We tend to create a new storyboard when we recognize a common theme in related
  view controllers. Just as with code, we don't want bloated storyboards with
  all kinds of unrelated things in there. Most of our storyboards have fewer
  than 10 scenes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scottberrevoets.com/2016/03/21/outlets-strong-or-weak/"&gt;Our outlets are defined
  carefully.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, even with these improvements everything is not peaches and cream.
There are definitely still problems. New versions of Xcode often change the XML
representation which leads to a noisy diff. Some properties can simply not be
set in IB meaning we're forced to break our "do everything in IB" rule.
Interface Builder has bugs we can't always work around.&lt;/p&gt;
&lt;p&gt;However, with our improved infrastructure and the points from above, we are
happy with how IB works for us. We don't have to write tons of Auto Layout code
(which would be incredibly painful due to the nature of our UIs), get a visual
representation of how a view looks without having to run the app after every
minor change, and maybe one day we can get our designers make changes to our UI
without developers' help.&lt;/p&gt;</content><category term="iOS Development"/><category term="Developer Experience"/><category term="Technology Adoption"/></entry><entry><title>Keeping the Lyft iOS App Accessible</title><link href="https://scottberrevoets.com/2017/01/18/keeping-the-lyft-ios-app-accessible/" rel="alternate"/><published>2017-01-18T00:00:00-08:00</published><updated>2017-01-18T00:00:00-08:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2017-01-18:/2017/01/18/keeping-the-lyft-ios-app-accessible/</id><summary type="html">&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;This article was written by me but originally published on the &lt;a href="https://eng.lyft.com/keeping-lyft-accessible-53155f0098b9"&gt;Lyft
Engineering Blog&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;At Lyft we’re in a unique position: every day we work on an app that affects
people in the real, physical world — not just the digital one. This has an
especially large impact on …&lt;/p&gt;</summary><content type="html">&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;This article was written by me but originally published on the &lt;a href="https://eng.lyft.com/keeping-lyft-accessible-53155f0098b9"&gt;Lyft
Engineering Blog&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;At Lyft we’re in a unique position: every day we work on an app that affects
people in the real, physical world — not just the digital one. This has an
especially large impact on visually impaired users, because our app is
easier to use than the real world alternatives — navigating a train station
or queueing up at a taxi stand. Lyft aims to make a product that is
accessible and easy to use for all of our users.&lt;/p&gt;
&lt;h2 id="accessibility-at-lyft"&gt;Accessibility at Lyft&lt;/h2&gt;
&lt;p&gt;If an app uses Apple’s standard controls and UI elements, it will likely already
work well with VoiceOver; however, Lyft’s UI deviates enough from standard
controls such that we don’t get that benefit out of the box. Another
complication is that many portions of the app are controlled by the server,
including a lot of the text for buttons and labels. Making these UI elements
compatible with VoiceOver often requires tweaking them manually, even if we use
native controls.&lt;/p&gt;
&lt;p&gt;Since we try to keep all of our UI-related code in Interface Builder, and
VoiceOver is just another form of UI, we have written a simple &lt;code&gt;UIView&lt;/code&gt;
extension that allows us to enable accessibility on most of our UI directly from
Interface Builder. In this extension, we add 2 properties to &lt;code&gt;UIView&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;accessibilitySources&lt;/code&gt;: An &lt;code&gt;IBOutletCollection&lt;/code&gt; of &lt;code&gt;UIView&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;&lt;code&gt;accessibilityFormat&lt;/code&gt;: a simple string that represents the format of the
  accessibility label, which is subsequently passed to &lt;code&gt;String(format:)&lt;/code&gt;. Every
  occurrence of &lt;code&gt;%@&lt;/code&gt; in this string will be replaced with the next element of
  the &lt;code&gt;accessibilitySources&lt;/code&gt;, and &lt;code&gt;[self]&lt;/code&gt; will automatically be replaced with
  the current view’s accessibilityLabel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can ctrl + drag UI elements into the &lt;code&gt;accessibilitySources&lt;/code&gt;, and by marking
&lt;code&gt;accessibilityFormat&lt;/code&gt; with &lt;code&gt;@IBInspectable&lt;/code&gt; we can specify the string and the
sources all from Interface Builder, keeping the code clean and to the point.&lt;/p&gt;
&lt;p&gt;For example, we have an accessibility format on the UILabel that displays the
selected ride mode:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Setting the accessibility format" src="/images/AccessibilityFormat.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[self]&lt;/code&gt; is replaced by the accessibility label, which for &lt;code&gt;UILabel&lt;/code&gt;s is the
text of the label itself. &lt;code&gt;%@&lt;/code&gt; is replaced by an accessibility source, which we
can set up like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Setting the accessibility sources" src="/images/AccessibilitySource.png"&gt;&lt;/p&gt;
&lt;p&gt;By disabling the accessibility label for the subtitle, the top label’s
accessibility label will read “Selected ride mode: Line. Carpool, 2 people
maximum.” without touching any code at all.&lt;/p&gt;
&lt;h2 id="changing-the-process"&gt;Changing the process&lt;/h2&gt;
&lt;p&gt;As we ramped up our VoiceOver efforts, we wanted to assess whether the changes
we made had a meaningful impact to end-users. As developers, we’re too familiar
with our own apps to make an honest call about their usability, and when it
comes to visual impairment, even a standard usability review could brush over
things that would be challenging to a blind or a visually impaired user.&lt;/p&gt;
&lt;p&gt;This is why we’re working with a dedicated accessibility expert, himself a
native VoiceOver user, to constantly validate our work. All the feedback we’ve
been getting from VoiceOver users have further motivated our investment in
accessibility. We have optimized VoiceOver in the main flows of our app, and we
run weekly regression tests to ensure consistency and stability. Our VoiceOver
user also works directly with QA engineers, to let them know what he is looking
for and what is missing.&lt;/p&gt;
&lt;p&gt;Over the last few months, we have made many improvements in various parts of our
app, but also in how seriously we take VoiceOver-related bugs: we block new
releases if VoiceOver users experience bugs when going through a ride. All new
features are expected to be optimized for VoiceOver from the start, and we are
working hard to optimize existing features as well.&lt;/p&gt;
&lt;p&gt;We think of accessibility as part of the user interface, just like labels,
buttons, and text fields. By having our developers implement support for
VoiceOver as part of the initial feature, our visually impaired users will be
able to use these features as easily as our regular users.&lt;/p&gt;</content><category term="iOS Development"/><category term="Engineering Culture"/></entry><entry><title>Silencing NSLog</title><link href="https://scottberrevoets.com/2016/08/01/silencing-nslog/" rel="alternate"/><published>2016-08-01T00:00:00-07:00</published><updated>2016-08-01T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2016-08-01:/2016/08/01/silencing-nslog/</id><summary type="html">&lt;p&gt;When your app has a lot of third-party dependencies, what often happens is that
those libraries log a bunch of things to the Xcode console to help their own
debugging. Unfortunately, a lot of these logs are useful only to the developers
of the library, but not the developers of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;When your app has a lot of third-party dependencies, what often happens is that
those libraries log a bunch of things to the Xcode console to help their own
debugging. Unfortunately, a lot of these logs are useful only to the developers
of the library, but not the developers of apps that integrate the library. For
example, they log things like &lt;code&gt;&amp;lt;SomeLibrary&amp;gt; (version 1.2.3) initialized&lt;/code&gt;, or
&lt;code&gt;&amp;lt;SomeLibrary&amp;gt; started &amp;lt;primary functionality&amp;gt;&lt;/code&gt;, sometimes with a long list of
parameters or input sources that are irrelevant to you.&lt;/p&gt;
&lt;p&gt;Finding your own log statements in a jungle of other logs can then be
very difficult and adds to the frustration of not being able to work the debugger
as you would like to.&lt;/p&gt;
&lt;p&gt;If a library is open source you can suggest a change by removing the log or
otherwise make it less obtrusive. However, if your change gets accepted at all,
that doesn't solve the immediate problem of being able to debug your own code
using the console.&lt;/p&gt;
&lt;p&gt;Meet &lt;code&gt;_NSSetLogCStringFunction()&lt;/code&gt;. This C function has been around in Foundation
for a long time, and while there is some
&lt;a href="https://support.apple.com/kb/TA45403?locale=en_US"&gt;documentation&lt;/a&gt; on it, it's
still a private method. However, that doesn't mean you can't use it in debug
mode when your logs are the most valuable!&lt;/p&gt;
&lt;p&gt;In short, this function lets you set a function pointer that can log C strings,
which &lt;code&gt;NSLog&lt;/code&gt; then uses instead of the normal implementation. You can do this
in two ways.&lt;/p&gt;
&lt;p&gt;The first one is by adding this to your Objective-C bridging header:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_NSSetLogCStringFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;and then use it like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;disableNSLog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#if&lt;/span&gt; &lt;span class="cp"&gt;DEBUG&lt;/span&gt;
    &lt;span class="n"&gt;_NSSetLogCStringFunction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="c1"&gt;// no actual logging, message just gets lost&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;If you want to stick to pure Swift, you can do so by adding this to your code
somewhere:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;_silgen_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_NSSetLogCStringFunction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setNSLogFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;convention&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;UnsafePointer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Int8&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="nb"&gt;UInt32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ObjCBool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;and then use it like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;disableNSLog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#if&lt;/span&gt; &lt;span class="cp"&gt;DEBUG&lt;/span&gt;
    &lt;span class="n"&gt;setNSLogFunction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="c1"&gt;// no actual logging, message just gets lost&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Obviously, you can do anything you want inside the closure, including writing to
a file, annotating the message with a date/time, passing it to your custom
logging library, etc.&lt;/p&gt;
&lt;p&gt;One downside of this is that Apple's frameworks use &lt;code&gt;NSLog&lt;/code&gt; extensively as well,
so in the above case of completely disabling logging, helpful messages get lost
as well. You won't be able to use &lt;code&gt;NSLog&lt;/code&gt; yourself either anymore, so I suggest
you use &lt;code&gt;print()&lt;/code&gt; or a custom logging framework that's not &lt;code&gt;NSLog&lt;/code&gt; based.&lt;/p&gt;
&lt;p&gt;If you're not afraid of doing (more) horrible things in your codebase, you can
avoid losing Apple frameworks' messages by parsing the stack trace and looking
at the framework that called this function and see if it's something you want to
let through:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;disableNSLog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#if&lt;/span&gt; &lt;span class="cp"&gt;DEBUG&lt;/span&gt;
    &lt;span class="n"&gt;_NSSetLogCStringFunction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="c1"&gt;// message is of type UnsafePointer&amp;lt;Int8&amp;gt; so first see if we can get a&lt;/span&gt;
        &lt;span class="c1"&gt;// normal String from that. Safety first!&lt;/span&gt;

        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromCString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;callStack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;NSThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callStackSymbols&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sourceString&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;callStack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;separatorSet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;NSCharacterSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;charactersInString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; -[]+?.,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;stackFrame&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sourceString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;componentsSeparatedByCharactersInSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separatorSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;frameworkName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stackFrame&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;frameworkName&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;UIKit&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;frameworkName&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Foundation&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;MyCustomLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;This discards all logs, except if they're coming from &lt;code&gt;UIKit&lt;/code&gt; or &lt;code&gt;Foundation&lt;/code&gt;.
The stack trace parsing is by no means safe (its format could change, for
example), but since it's wrapped in &lt;code&gt;#if DEBUG&lt;/code&gt; directives it won't mess with
anything in the App Store build.&lt;/p&gt;
&lt;p&gt;Note that static libraries are part of your main app's target, which means you
have to filter out logs from your own target to hide those.&lt;/p&gt;
&lt;p&gt;You could even go a bit farther and check the message for keywords you like or
don't like and make a decision on whether you want to log or not. Keep in mind,
though, that any work you do here needs to be fast as you don't always know just
how much is being logged.&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/><category term="Developer Experience"/></entry><entry><title>Outlets: strong! or weak?</title><link href="https://scottberrevoets.com/2016/03/21/outlets-strong-or-weak/" rel="alternate"/><published>2016-03-21T00:00:00-07:00</published><updated>2016-03-21T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2016-03-21:/2016/03/21/outlets-strong-or-weak/</id><summary type="html">&lt;p&gt;There are a lot of styles out there when it comes to using Interface Builder
outlets in Swift. Even Apple's documentation and sample code isn't always
consistent. The most common one, the one Apple uses in its sample code, follows
this pattern:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@IBOutlet private weak var someLabel: UILabel!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let's break …&lt;/p&gt;</summary><content type="html">&lt;p&gt;There are a lot of styles out there when it comes to using Interface Builder
outlets in Swift. Even Apple's documentation and sample code isn't always
consistent. The most common one, the one Apple uses in its sample code, follows
this pattern:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@IBOutlet private weak var someLabel: UILabel!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let's break this down by keyword:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@IBOutlet&lt;/code&gt; makes Interface Builder recognize the outlet&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt; ensures the outlet isn't accessed outside the current class&lt;/li&gt;
&lt;li&gt;&lt;code&gt;weak&lt;/code&gt; is used because in most situations the owner of the outlet isn't the same as the owner of the view. For example, a view controller doesn't own &lt;code&gt;someLabel&lt;/code&gt; - the view controller's &lt;code&gt;view&lt;/code&gt; does.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;var&lt;/code&gt; because outlets are, by definition, set &lt;em&gt;after&lt;/em&gt; initialization&lt;/li&gt;
&lt;li&gt;&lt;code&gt;someLabel: UILabel&lt;/code&gt; is just an example, this applies to outlets of any kind&lt;/li&gt;
&lt;li&gt;&lt;code&gt;!&lt;/code&gt;, or the implicitly unwrapped optional, is convenient because you don't have to litter your code with &lt;code&gt;?&lt;/code&gt; and &lt;code&gt;if let&lt;/code&gt;s (or just &lt;code&gt;!&lt;/code&gt;) everywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While at first this seems like a solid approach, at Lyft we quickly realized we
weren't fans of this one-size-fits-all way of defining outlets. Instead, the
behavior and consequences of the different elements should define the outlet's
exact syntax, just like any other variable.&lt;/p&gt;
&lt;p&gt;For example, if there is a code path that removes an outlet from its superview,
or the outlet is (intentionally) not hooked up in the storyboard, it needs to be
an optional because the outlet is not guaranteed to be there when it's accessed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@IBOutlet private var someLabel: UILabel?&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If there is no code path that re-adds the outlet to the view hierarchy, it would
also be good to make it &lt;code&gt;weak&lt;/code&gt; to not hold on to it unnecessarily when it gets
removed:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@IBOutlet private weak var someLabel: UILabel?&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This ensures that if the label is removed from the superview, it's not being
kept in memory by the strong reference in the view controller. In the most
common case, where there is an outlet that will always be there, a strong,
implicitly unwrapped optional is appropriate:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@IBOutlet private var someLabel: UILabel!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The outlet isn't &lt;code&gt;weak&lt;/code&gt; in case the code ever changes so that there &lt;em&gt;is&lt;/em&gt; a code
path that removes the view from the view hierarchy but you forget to update the
optionality of the property. The object will stay in memory and using it won't
crash your app.&lt;/p&gt;
&lt;p&gt;These examples all follow 3 simple rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;!&lt;/code&gt; needs a guarantee that the view exists, so always use &lt;code&gt;strong&lt;/code&gt; to provide
   that guarantee&lt;/li&gt;
&lt;li&gt;If it's possible the view isn't part of the view hierarchy, use &lt;code&gt;?&lt;/code&gt; and
   appropriate optional-handling (optional binding/chaining) for safety&lt;/li&gt;
&lt;li&gt;If you don't need a view anymore after removing it from the view hierarchy,
   use &lt;code&gt;weak&lt;/code&gt; so it gets removed from memory.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Applying these three rules means you properly use the optional semantics. After
all, using &lt;code&gt;!&lt;/code&gt; for a view that may not exist is no different than defining any
other property as an implicitly unwrapped optional that may not exist.&lt;/p&gt;</content><category term="iOS Development"/></entry><entry><title>@objc class prefixes fixed in Xcode 7 beta 4</title><link href="https://scottberrevoets.com/2015/07/23/objc-class-prefixes-fixed-in-xcode-7-beta-4/" rel="alternate"/><published>2015-07-23T00:00:00-07:00</published><updated>2015-07-23T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2015-07-23:/2015/07/23/objc-class-prefixes-fixed-in-xcode-7-beta-4/</id><summary type="html">&lt;p&gt;Back in December I &lt;a href="/2014/12/15/at-objc-creates-a-wrong-class-name-in-objective-c/"&gt;wrote&lt;/a&gt; about what I thought was a bug in the Swift compiler that would expose the wrong class name for a Swift class in Objective-C. I then later &lt;a href="https://devforums.apple.com/message/1072175#1072175"&gt;found out&lt;/a&gt; everything worked as intended and I had just misunderstood what &lt;code&gt;@objc()&lt;/code&gt; exactly did. Apparently it was …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Back in December I &lt;a href="/2014/12/15/at-objc-creates-a-wrong-class-name-in-objective-c/"&gt;wrote&lt;/a&gt; about what I thought was a bug in the Swift compiler that would expose the wrong class name for a Swift class in Objective-C. I then later &lt;a href="https://devforums.apple.com/message/1072175#1072175"&gt;found out&lt;/a&gt; everything worked as intended and I had just misunderstood what &lt;code&gt;@objc()&lt;/code&gt; exactly did. Apparently it was never supposed to modify the class name at compile time, but only at runtime.&lt;/p&gt;
&lt;p&gt;I'm sure changing the class name just at runtime has its uses, but in my opinion, this would be most helpful if it also affected the compile time name of Objective-C classes. It allows you to namespace your classes in Objective-C using your three-letter prefix, without needing that prefix in Swift because you could namespace by way of modules.&lt;/p&gt;
&lt;p&gt;And fortunately, in Xcode 7 beta 4, they have actually modified the &lt;code&gt;@objc()&lt;/code&gt; notation so that it &lt;em&gt;does&lt;/em&gt; do this. For example, if I have a Swift module that I want others to be able to use in their Objective-C codebase, I could write a class like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;@objc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SDCMyClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="bp"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;NSObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;And in &lt;code&gt;MyProject-Swift.h&lt;/code&gt; the Objective-C class is defined as:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;SWIFT_CLASS_NAMED&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;MyClass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;SDCMyClass&lt;/span&gt; : &lt;span class="bp"&gt;NSObject&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonnull&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;OBJC_DESIGNATED_INITIALIZER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;In Swift I can simply use the class as &lt;code&gt;MyClass&lt;/code&gt;, but in Objective-C its name is &lt;code&gt;SDCMyClass&lt;/code&gt;, which ensures it doesn't collide with other classes named &lt;code&gt;MyClass&lt;/code&gt;. Needless to say, I'm very happy they changed this behavior, it makes much more sense now.&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/></entry><entry><title>The power of UIStackView</title><link href="https://scottberrevoets.com/2015/06/13/the-power-of-uistackview/" rel="alternate"/><published>2015-06-13T00:00:00-07:00</published><updated>2015-06-13T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2015-06-13:/2015/06/13/the-power-of-uistackview/</id><summary type="html">&lt;p&gt;I was in the audience for "Implementing UI Designs in Interface Builder" at WWDC, where Apple touted &lt;code&gt;UIStackView&lt;/code&gt; as a new, better way to lay out your views that in a lot of cases didn't require Auto Layout.&lt;/p&gt;
&lt;p&gt;While the presentation looked good, I wasn't quite sure this solved a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I was in the audience for "Implementing UI Designs in Interface Builder" at WWDC, where Apple touted &lt;code&gt;UIStackView&lt;/code&gt; as a new, better way to lay out your views that in a lot of cases didn't require Auto Layout.&lt;/p&gt;
&lt;p&gt;While the presentation looked good, I wasn't quite sure this solved a real problem, as the required constraints weren't too complicated to build in the first pace. However, after I found some time to play around with &lt;code&gt;UIStackView&lt;/code&gt;, I'm convinced. This view is very, very powerful and can make building common UIs a lot simpler. Take, for example, a number grid:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary aria-label="Toggle code block"&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;[1] [2] [3]
[4] [5] [6]
[7] [8] [9]
    [0]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;It would take a while to build this kind of UI in Auto Layout. You would have to create constraints between individual labels, make the labels the same size everywhere, make the spacing between all the labels equal, and avoid hardcoding any numbers to keep the whole thing adaptive. This can be a tedious process in Interface Builder, but imagine you're building this in code. It would take forever, especially after debugging your UI.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;UIStackView&lt;/code&gt;, doing all of this takes about 30 seconds. After dragging out all the labels, you just need to embed every row in its own stack view. Set the distribution (in code that's &lt;code&gt;UIStackViewDistribution&lt;/code&gt;) for these stack views to "fill equally" (&lt;code&gt;.FillEqually&lt;/code&gt;), then embed all four stack views in their own stack view.&lt;/p&gt;
&lt;p&gt;&lt;img alt="UIStackView example" src="/images/UIStackView.png"&gt;&lt;/p&gt;
&lt;p&gt;The top-level, vertical stack view should get top/leading/trailing/bottom space to its superview (or the layout guides), the 4 horizontal stack views an "equal width" constraint to their superview. Finally, center the text of the individual labels (you can select all labels at once and do this with 1 action). Done - that's it.&lt;/p&gt;
&lt;p&gt;But it gets better. Say you want to conditionally show or hide the &lt;code&gt;0&lt;/code&gt; label at the bottom. I don't know why you would want that, but just go with it 😛&lt;/p&gt;
&lt;p&gt;To do this, all you have to is &lt;strong&gt;toggle the&lt;/strong&gt; &lt;code&gt;hidden&lt;/code&gt; &lt;strong&gt;property of that label&lt;/strong&gt;. The containing stack view will automatically reposition its subviews. If you put that line in an animation block, it will reposition its subviews in an animated fashion.&lt;/p&gt;
&lt;p&gt;That last part is a very welcome feature for developers that work with a lot of dynamic views. Instead of creating redundant constraints with lower priorities, removing views from their view hierarchies, and re-adding the view and all its constraints if the new views needs to be re-shown, you can simply toggle &lt;code&gt;hidden&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;As more people get their hands on &lt;code&gt;UIStackView&lt;/code&gt; I'm sure it will show off more of its powers, but needless to say I'm sold. Too bad I can't use it for a while...&lt;/p&gt;</content><category term="iOS Development"/><category term="Developer Experience"/></entry><entry><title>@objc creates a wrong class name in Objective-C</title><link href="https://scottberrevoets.com/2014/12/15/objc-creates-a-wrong-class-name-in-objective-c/" rel="alternate"/><published>2014-12-15T00:00:00-08:00</published><updated>2014-12-15T00:00:00-08:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2014-12-15:/2014/12/15/objc-creates-a-wrong-class-name-in-objective-c/</id><summary type="html">&lt;p&gt;A few months ago, I decided I'd get started porting &lt;a href="https://github.com/sberrevoets/SDCAlertView"&gt;SDCAlertView&lt;/a&gt; to Swift, but I was only a few minutes in until I ran into a problem I had no idea how to solve: I couldn't get my class names right in both Swift and Objective-C. Even though there are …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few months ago, I decided I'd get started porting &lt;a href="https://github.com/sberrevoets/SDCAlertView"&gt;SDCAlertView&lt;/a&gt; to Swift, but I was only a few minutes in until I ran into a problem I had no idea how to solve: I couldn't get my class names right in both Swift and Objective-C. Even though there are copious amounts of documentation covering the interoperability of Swift and Objective-C, somehow I couldn't get it to work and I brushed it off as me being stupid.&lt;/p&gt;
&lt;p&gt;Tonight I tried again, and after some more research it turned out that the behavior I saw was actually a bug in the compiler! I'm surprised that the latest Xcode version is 6.1.1 and that apparently not enough people have run into this problem for Apple to make it a priority.&lt;/p&gt;
&lt;p&gt;The bug can easily be reproduced by creating an Objective-C project in Xcode, and then adding the following Swift class:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Swift&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;UIKit&lt;/span&gt;

&lt;span class="kr"&gt;@objc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SDCMyLabel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyLabel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;UILabel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;You would expect that, once you import &lt;code&gt;MyProject-Swift.h&lt;/code&gt; in your Objective-C class, you could instantiate a class named &lt;code&gt;SDCMyLabel&lt;/code&gt;. However, instead, you can only instantiate a class named &lt;code&gt;MyLabel&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I found this very recent &lt;a href="https://stackoverflow.com/questions/26132823/name-of-swift-class-when-exposed-to-objective-c-code-does-not-respect-the-objc"&gt;Stack Overflow&lt;/a&gt; question which pretty much asks the same thing. "milos" gives a great answer by explaining the observed behavior in Xcode 6.0.1, and the expected behavior according to the WWDC session &lt;a href="https://developer.apple.com/videos/wwdc/2014/"&gt;video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After reading the answer and watching the relevant parts of the vide, I slightly changed my previously-drawn conclusion from "I'm stupid" to "Xcode's stupid" and filed &lt;a href="rdar://19261044"&gt;rdar://19261044&lt;/a&gt;. If you're running into the same problem, please duplicate and cross your fingers the engineers at the fruit company will fix it soon.&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/></entry><entry><title>Dev-only iPhones</title><link href="https://scottberrevoets.com/2014/10/20/dev-only-iphones/" rel="alternate"/><published>2014-10-20T00:00:00-07:00</published><updated>2014-10-20T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2014-10-20:/2014/10/20/dev-only-iphones/</id><summary type="html">&lt;p&gt;With today's release of iOS 8.1, most app developers are looking at 4
significantly different iOS versions they will be supporting: iOS 7.0, iOS 7.1,
iOS 8.0, and iOS 8.1. Factoring in the number of devices (iPhone 4S, iPhone 5,
iPhone 5s, iPhone 6, and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;With today's release of iOS 8.1, most app developers are looking at 4
significantly different iOS versions they will be supporting: iOS 7.0, iOS 7.1,
iOS 8.0, and iOS 8.1. Factoring in the number of devices (iPhone 4S, iPhone 5,
iPhone 5s, iPhone 6, and iPhone 6 Plus) that run these OS versions, there is a
grand total of &lt;strong&gt;16&lt;/strong&gt; different configurations. That's without even counting the
iPhone 5c, which is internally pretty much the same as the 5, or the
&lt;a href="https://www.macrumors.com/2014/09/29/ios-8-major-updates/"&gt;rumored&lt;/a&gt; iOS 8.2 and
iOS 8.3 updates.&lt;/p&gt;
&lt;p&gt;Assuming an average off-contract price of $400 for these models, that means
you're looking at $6,400 for 1 set of iPhones used for development. Creating a
universal app? Your total will now exceed $10,000.&lt;/p&gt;
&lt;p&gt;So now you have these 16 phones that will in most cases be used for testing
maybe a handful of apps, that have chips and software functionality in them that
will be used very little (if at all), and will most of the time just sit in some
desk drawer with a dead battery. I could think of better ways to spend money.&lt;/p&gt;
&lt;p&gt;This problem could have a very simple solution: dev-only iPhones. Remove or
disable the cellular chip (you can simulate cellular networks using the Network
Link Conditioner), give it an 8GB storage chip, remove apps such as Weather,
Stocks, Calculator, Clock, etc., disable the App Store for all but the
developer's own apps, allow any supported iOS version to be installed using
Xcode, and sell at-cost, but only to developers in the iOS Developer Program.&lt;/p&gt;
&lt;p&gt;By disabling cellular and dumbing the OS down to only include parts that
developers can interact with, it becomes pretty useless for people who are just
trying to look for a sweet deal on an iPhone/iPod touch. The win for developers
is that they only need 1 of each device, but they're also
&lt;a href="https://www.macrumors.com/2014/09/23/iphone-6-parts-cost-samsung-a8/"&gt;cheaper&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You could even take it a step further and set memory, CPU and screen size limits
(meaning only use 4" of the available 5.5"), allowing you to simulate an iPhone
5s on an iPhone 6 Plus. Now developers only need to buy the iPhone 6 Plus to be
mostly covered, though I'd still recommend also getting an iPhone 5 or iPhone 5c
for 32-bit devices.&lt;/p&gt;
&lt;p&gt;I may be way off course here due to technical implications or limitations that
I'm not aware of. There are also still cases in which you'd need an actual
device on the actual software as consumers use it. Developers don't always need
to test against &lt;strong&gt;every&lt;/strong&gt; iOS version on &lt;strong&gt;every&lt;/strong&gt; supported iOS device. But for
developers who do and don't want to spend the money on all these different
devices, a dev-only iPhone may be exactly what they need.&lt;/p&gt;
&lt;div class="admonition update"&gt;
&lt;p class="admonition-title"&gt;Update (February 2026)&lt;/p&gt;
&lt;p&gt;This was never really realistic for a variety of reasons, but I still think
the cost of entry for iOS development is unnecessarily high. The simulator
is still pretty good and has gotten much better over the years, but entire
classes of apps can't be simulated properly. The number of software updates,
device matrix, and hardware/software capabilities make dev-only iPhones also
not really scalable.&lt;/p&gt;
&lt;p&gt;The Apple enthusiasts still get new phones regularly enough that used phones
have become cheap enough to cover a bit more of the testing matrix too.&lt;/p&gt;
&lt;/div&gt;</content><category term="iOS Development"/><category term="Testing"/><category term="Developer Experience"/></entry><entry><title>UIMenuController and the responder chain</title><link href="https://scottberrevoets.com/2014/09/15/uimenucontroller-and-the-responder-chain/" rel="alternate"/><published>2014-09-15T00:00:00-07:00</published><updated>2014-09-15T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2014-09-15:/2014/09/15/uimenucontroller-and-the-responder-chain/</id><summary type="html">&lt;p&gt;The responder chain is a very important paradigm in the world of iOS development, and not terribly hard to understand. Dozens of articles have been written about it, and with some examples, the concept of finding a responder to a certain event by traversing a chain of potential responders is …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The responder chain is a very important paradigm in the world of iOS development, and not terribly hard to understand. Dozens of articles have been written about it, and with some examples, the concept of finding a responder to a certain event by traversing a chain of potential responders is fairly straight-forward.&lt;/p&gt;
&lt;p&gt;But today it completely threw me off. The goal was very simple and has been done many times before: showing a label whose text can be copied to the clipboard. Having never worked with &lt;code&gt;UIMenuController&lt;/code&gt;, I fired up Google and of course found an excellent &lt;a href="https://nshipster.com/uimenucontroller/"&gt;NSHipster&lt;/a&gt; article near the top.&lt;/p&gt;
&lt;p&gt;I did as the article said. I created my &lt;code&gt;UILabel&lt;/code&gt; subclass (only accepting &lt;code&gt;copy:&lt;/code&gt; as an action it can perform), added my gesture recognizer, and configured and showed the &lt;code&gt;UIMenuController&lt;/code&gt;. It worked, but instead of only showing the Copy menu item, it also showed the Select All item.&lt;/p&gt;
&lt;p&gt;Well, that's weird. I implemented &lt;code&gt;canPerformAction:withSender:&lt;/code&gt; like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;BOOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;canPerformAction:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SEL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;withSender:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;sender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;I made sure that this method really only returned &lt;code&gt;YES&lt;/code&gt; for the Copy item, proceeded to explicitly return &lt;code&gt;NO&lt;/code&gt; for &lt;code&gt;selectAll:&lt;/code&gt; and, when that failed as well, even changed the implementation of this method to just return &lt;code&gt;NO&lt;/code&gt; for &lt;strong&gt;any&lt;/strong&gt; item. But Select All doesn't take &lt;code&gt;NO&lt;/code&gt; for an answer, and it stubbornly showed up anyway! I was baffled and could not get rid of this Select All item.&lt;/p&gt;
&lt;p&gt;I did some research, and learned that &lt;code&gt;UIMenuController&lt;/code&gt; uses the responder chain to figure out what items to show. Furthermore, the documentation for &lt;code&gt;canPerformAction:withSender:&lt;/code&gt; read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This default implementation of this method returns YES if the responder class implements the requested action and calls the next responder if it does not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That would explain the problem, if it weren't for the fact that Select All was the only other item that showed. Cut, Paste, Select, etc. did not. What was so special about Select All that no matter what I did, it always decided to make an unwanted appearance?&lt;/p&gt;
&lt;p&gt;Finally I saw it. One of the last methods of the view controller that created this label had a method named, you guessed it, &lt;code&gt;selectAll:&lt;/code&gt;. I didn't immediately connect the dots, but at least renaming that method to &lt;code&gt;selectAllContacts:&lt;/code&gt; (which was a better name for that method anyway) got rid of Select All.&lt;/p&gt;
&lt;p&gt;But how? I returned &lt;code&gt;NO&lt;/code&gt; from my label's &lt;code&gt;canPerformAction:withSender:&lt;/code&gt; for all actions except &lt;code&gt;copy:&lt;/code&gt;. This means that for all other actions (see the informal &lt;code&gt;UIResponderStandardEditActions&lt;/code&gt;), the next responder in the chain would be called. And (if necessary) the next, and the next.&lt;/p&gt;
&lt;p&gt;At some point, my view controller, which participates in the responder chain, became the first responder and returned &lt;code&gt;YES&lt;/code&gt; for the &lt;code&gt;selectAll:&lt;/code&gt; action, simply because the method was implemented and part of &lt;code&gt;UIResponderStandardEditActions&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if implementing a method in that protocol is all that's needed to show the corresponding menu item, that would mean that implementing &lt;code&gt;canPerformAction:withSender:&lt;/code&gt; in my &lt;code&gt;UILabel&lt;/code&gt; subclass was unnecessary. I removed the method altogether and sure enough, the Copy menu item was still there. Problem solved.&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/></entry><entry><title>Xcode &amp; Objective-C Oddities</title><link href="https://scottberrevoets.com/2014/08/10/xcode-objective-c-oddities/" rel="alternate"/><published>2014-08-10T00:00:00-07:00</published><updated>2014-08-10T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2014-08-10:/2014/08/10/xcode-objective-c-oddities/</id><summary type="html">&lt;p&gt;Any developer that has worked with Xcode to write a little more than just "Hello, World" knows that Xcode and Objective-C have their quirks. Chances are you have heard of &lt;a href="https://twitter.com/TextFromXcode"&gt;@TextFromXcode&lt;/a&gt;, the Twitter handle that portrays Xcode as a high school bully in fake text conversations like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Xcode Bully" src="https://cl.ly/image/0I2P191S0Q2k/20140227.PNG"&gt;&lt;/p&gt;
&lt;p&gt;But it's …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Any developer that has worked with Xcode to write a little more than just "Hello, World" knows that Xcode and Objective-C have their quirks. Chances are you have heard of &lt;a href="https://twitter.com/TextFromXcode"&gt;@TextFromXcode&lt;/a&gt;, the Twitter handle that portrays Xcode as a high school bully in fake text conversations like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Xcode Bully" src="https://cl.ly/image/0I2P191S0Q2k/20140227.PNG"&gt;&lt;/p&gt;
&lt;p&gt;But it's not always Xcode that makes Apple platform developers sometimes frown and sigh. Sometimes it's the developers themselves, sometimes it's the documentation, and sometimes a hidden gem from within Apple frameworks makes an appearance. I've compiled a short list of things I've encountered. Because it's Sunday and I didn't have anything better to do.&lt;/p&gt;
&lt;h2 id="uigobblergesturerecognizer"&gt;&lt;code&gt;UIGobblerGestureRecognizer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Say what? A "&lt;a href="https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIGobblerGestureRecognizer.h"&gt;&lt;code&gt;gobbler&lt;/code&gt;&lt;/a&gt;" recognizer? Does it recognize when the user imitates a turkey? Well, maybe, but according to &lt;a href="https://twitter.com/ortwingentz/status/225508227234791424"&gt;BJ Homer&lt;/a&gt;, it is used to avoid recognition of a gesture while animations are in progress. Ah of course! Now the name "gobbler" makes perfect sense! 😶&lt;/p&gt;
&lt;h2 id="uitapandahalfrecognizer"&gt;&lt;code&gt;UITapAndAHalfRecognizer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Speaking of gesture recognizers, there's another remarkable one that lives in the private section of UIKit: &lt;code&gt;UITapAndAHalfRecognizer&lt;/code&gt;. This is a private subclass of &lt;code&gt;UIGestureRecognizer&lt;/code&gt; that records "a tap and a half".&lt;/p&gt;
&lt;p&gt;So what does that mean? Does it detect whether the user goes in for a second tap, but never actually touches the screen? Or does the user touch the screen ever so slightly that the second tap can hardly be considered a complete tap? Nope! This recognizer fires when a second tap stays on the screen. Not sure for what functionality Apple needs this, but it's been around since at least iOS 4, so it probably has a purpose.&lt;/p&gt;
&lt;h2 id="naming-is-hard"&gt;Naming is hard&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;br&gt;
- Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Naming &lt;strong&gt;is&lt;/strong&gt; hard, but Objective-C developers always say that verbosity is one of Objective-C's strengths because its naming conventions are self-documenting. Normally I'd agree, but in this case, I think Apple may want to consider a different name.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developer.apple.com/library/prerelease/ios/releasenotes/General/iOS80APIDiffs/frameworks/HomeKit.html"&gt;&lt;code&gt;HMCharacteristicValueLockMechanismLastKnownActionUnsecuredUsingPhysicalMovementExterior&lt;/code&gt;&lt;/a&gt; is a brand new constant in iOS 8 and has got to be one of the longest constants that's available in iOS. Try saying it without taking a breath in the middle. &lt;/p&gt;
&lt;p&gt;I found it in the iOS 8 API diffs, but it did make me wonder. What is the longest Objective-C method available in Cocoa Touch? Well, a quick Google search led to a blog post by &lt;a href="https://initwithstyle.net/2013/10/in-search-of-the-longest-method"&gt;Stuart Sharpe&lt;/a&gt;, who used the Objective-C runtime to generate a list of methods in the iOS 7 SDK.&lt;/p&gt;
&lt;p&gt;Turns out, the longest method in the iOS 7 SDK is&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CUIShapeEffectStack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shapeEffectSingleBlurFrom&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nl"&gt;withInteriorFill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                         &lt;/span&gt;&lt;span class="nl"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                       &lt;/span&gt;&lt;span class="nl"&gt;blurSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nl"&gt;innerGlowRed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="nl"&gt;innerGlowGreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="nl"&gt;innerGlowBlue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nl"&gt;innerGlowOpacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="nl"&gt;innerShadowRed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nl"&gt;innerShadowGreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nl"&gt;innerShadowBlue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="nl"&gt;innerShadowOpacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nl"&gt;outerGlowRed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="nl"&gt;outerGlowGreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="nl"&gt;outerGlowBlue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nl"&gt;outerGlowOpacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="nl"&gt;outerShadowRed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="nl"&gt;outerShadowGreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="nl"&gt;outerShadowBlue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="nl"&gt;outerShadowOpacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="nl"&gt;hasInsideShadowBlur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nl"&gt;hasOutsideShadowBlur&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Unless iOS 8 introduces a longer method name, this one takes the cake with 22 arguments and 352 characters. If you have Xcode configured to line-break at 80 characters (yes, some people still do that), this method signature alone, without any arguments, takes up 5 lines.&lt;/p&gt;
&lt;p&gt;Another beauty of a method lives in Core Animation and its method signature is &lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;CAMediaTimingFunction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;functionWithControlPoints&lt;/span&gt;&lt;span class="o"&gt;::::&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;&lt;code&gt;::::&lt;/code&gt;? Is that even valid syntax? Yes, and you call the method like this:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;CAMediaTimingFunction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;functionWithControlPoints&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;.50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Was an array really too much to ask...?&lt;/p&gt;
&lt;h2 id="nsdate-nildate"&gt;&lt;code&gt;[NSDate nilDate]&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This one has made the rounds throughout the developer community before, but I'm adding it here in case you haven't seen it yet. Try running the following code:&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Objective-C&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="bp"&gt;NSCalendar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;NSCalendar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;currentCalendar&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;NSCalendarUnitYear&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fromDate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;toDate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;NSDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;In the console log, you'll find the following output:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;*** -[__NSCFCalendar components:fromDate:toDate:options:]: fromDate cannot be nil&lt;br&gt;
I mean really, what do you think that operation is supposed to mean with a nil fromDate?&lt;br&gt;
An exception has been avoided for now.&lt;br&gt;
A few of these errors are going to be reported with this complaint, then further violations will simply silently do whatever random thing results from the nil.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Either a grumpy Apple developer woke up at the wrong side of the bed or has a great sense of humor. In any case, I wouldn't mind if more sarcastic warnings started popping up in Xcode's console.&lt;/p&gt;
&lt;h2 id="defying-the-uncertainty-principle-in-ios"&gt;Defying the Uncertainty Principle in iOS&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;[I]n 1927, Werner Heisenberg stated that the more precisely the position of some particle is determined, the less precisely its momentum can be known, and vice versa.&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Uncertainty_principle"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that's true, and it's fairly safe to assume that it is, I'd avoid using &lt;code&gt;-[CLLocation speed]&lt;/code&gt; for apps like radar detectors. I wonder if we're ever going to get a &lt;code&gt;-[CLSpeed location]&lt;/code&gt; method, which has a more accurate speed and a less accurate location.&lt;/p&gt;
&lt;h2 id="xcode-at-it-again"&gt;Xcode at it again&lt;/h2&gt;
&lt;p&gt;Lastly, the following is a screenshot I personally took at work that completely baffled me.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/XcodeScreenshot.png" style="width: 700px; margin: 0 auto; display: block;"&gt;&lt;/p&gt;
&lt;p&gt;This would not go away, even after cleaning the build folder and rebuilding. In the end I resolved the problem by running&lt;/p&gt;
&lt;details class="code-block" open&gt;&lt;summary&gt;&lt;span class="code-block-arrow" aria-hidden="true"&gt;&lt;/span&gt;&lt;span&gt;Bash&lt;/span&gt;&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;stash
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;--hard&lt;span class="w"&gt; &lt;/span&gt;HEAD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;p&gt;Then, after a clean build and &lt;code&gt;git stash pop&lt;/code&gt; the errors finally went away...&lt;/p&gt;
&lt;p&gt;That's just a few things I've found while working with Xcode and Objective-C over the years. If you have more, please share!&lt;/p&gt;</content><category term="iOS Development"/><category term="Debugging"/><category term="Developer Experience"/></entry><entry><title>Objective-C prefixes: a thing of the past?</title><link href="https://scottberrevoets.com/2014/07/25/objective-c-prefixes-a-thing-of-the-past/" rel="alternate"/><published>2014-07-25T00:00:00-07:00</published><updated>2014-07-25T00:00:00-07:00</updated><author><name>Scott Berrevoets</name></author><id>tag:scottberrevoets.com,2014-07-25:/2014/07/25/objective-c-prefixes-a-thing-of-the-past/</id><summary type="html">&lt;p&gt;This past week, there was, again, a lot to do about Objective-C and prefixing. To most iOS developers, the story sounds familiar: one camp is strongly in favor, another camps is strongly against, and a third camp couldn't really care less.&lt;/p&gt;
&lt;p&gt;Unless I'm unaware of any other platforms where the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This past week, there was, again, a lot to do about Objective-C and prefixing. To most iOS developers, the story sounds familiar: one camp is strongly in favor, another camps is strongly against, and a third camp couldn't really care less.&lt;/p&gt;
&lt;p&gt;Unless I'm unaware of any other platforms where the discussion was also a hot topic, this time I was at least a little responsible for instigating a debate that will never see a clear winner, with the following tweet:&lt;/p&gt;
&lt;blockquote class="twitter-tweet" lang="en" align="center"&gt;&lt;p&gt;&lt;a href="https://twitter.com/bobmccune"&gt;@bobmccune&lt;/a&gt; &lt;a href="https://twitter.com/invalidname"&gt;@invalidname&lt;/a&gt; Also no option to enter class prefix anymore, even for Objective-C projects&lt;/p&gt;&amp;mdash; Scott Berrevoets (@ScottBerrevoets) &lt;a href="https://twitter.com/ScottBerrevoets/statuses/492012762940588033"&gt;July 23, 2014&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;p&gt;Let's first clear up that Swift doesn't &lt;strong&gt;need&lt;/strong&gt; to have class prefixes, because it has built-in support for namespacing through modules. From what I read, earlier Xcode 6/Swift betas did not have module support, but at least we know it's coming before 1.0 hits.&lt;/p&gt;
&lt;p&gt;However, this doesn't solve any of the problems Objective-C has, and so it was surprising to see this field was removed when creating a new Objective-C project. You can still set this prefix per project &lt;strong&gt;after&lt;/strong&gt; you create it, but since most Xcode templates create source files for you, those files will be created without a prefix.&lt;/p&gt;
&lt;p&gt;I noticed the lack of this option, as well as the lack of a file template for Objective-C categories, back in beta 2 and immediately filed two bugs. The missing file template is as of this writing still open, but the class prefix got closed a few days later. Normally, radars aren't known for their wealth of information related to the issue the radar was filed for, but Apple Engineering made an exception this time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;After much deliberation, engineering has removed this feature.&lt;/p&gt;
&lt;p&gt;This was removed intentionally. We are no longer encouraging the use of prefixes for app code, and for frameworks, you can create a prefix in the Project Inspector after creating the project.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay, so no more prefixes for app code. Didn't see that coming. Does Apple now encourage developers to start making extensive use of frameworks?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No. If you want to use a prefix, you can set one in the project inspector. Especially for frameworks, this is easy since the template creates no source files that should be prefixed. If you really want to prefix the classes in your main app binary, you might need to rename the few that are created initially, but the recommendation is generally that frameworks should use prefixes (in Obj-C, not in Swift) to avoid namespace issues, and apps generally don't need to.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The key part here is in the last few words: "don't need to".&lt;/p&gt;
&lt;p&gt;Third-party libraries, especially frameworks that don't ship with the source code, need a prefix, because the chances of naming collisions with other code or, even worse, other libraries is significant. Users of the libraries can't (and even if they can, are likely not willing to) change the name of your classes because they collide with some other library's code.&lt;/p&gt;
&lt;p&gt;"App code" on the other hand, is very unique to one particular app. It contains the UI and some of the business logic that puts your app together. Most view controllers, for example, are app code. App code is not likely to be reused, because it's very specific in what it does and is therefore unlikely to collide with other classes (assuming you name your classes well). If you think "well, this functionality may be reused in some other project", it's a great candidate for a framework!&lt;/p&gt;
&lt;p&gt;I was always a big fan of the class prefixes, and while it was sometimes hard to come up with what prefix to use, I've come to actually &lt;strong&gt;like&lt;/strong&gt; how they look, too. Classes that don't have a prefix feel like they're missing something. However, the guideline of "prefix frameworks, not app code" does make sense, so I will start using that from now on as well.&lt;/p&gt;</content><category term="iOS Development"/><category term="Technology Adoption"/></entry></feed>