That Weird Obstable of Interface Builder When You Get Started With iOS Development

A very strange obstacle to overcome when you just get started with iOS or macOS programming is to use custom views or view controllers. How does this magic even work? And what do the steps mean that you have to perform? When you use a Xcode template, you get a Storyboard or a Xib with the most important components for an initial, empty app to display something on screen. This is accompanied by an AppDelegate and a custom ViewController class. If you don’t know anything and just get started developing for iOS, say, then this is a good place to start hacking away: after all, the bare-bones infrastructure has been handled for you.

Continue reading …

Xcode Bug Turns Out To Be the Hardened Runtime Setting

What I called an Xcode bug last week turned out to be a broken project configuration that was absolutely my fault. Back when Hardened Runtime was introduced, I switched it on at the Xcode project level, not just for the app target. When you set “Enable Hardened Runtime” on the project level, all targets inherit this setting: the app, the unit tests, and the UI tests. With Xcode 11, it now turns out that hardening the runtime for the test runner broke an internal library lookup in perfect accordance with the utility of the Hardened Runtime settings.

Continue reading …

Xcode 11 Displays Crash Logs in Context of Your Projects

For all throughout human history, you had to symbolicate your user’s crash logs using atos or a 3rd party tool to get human-readable output. Otherwise, you will not know the symbol or method name of your app’s parts that are involved and see memory offsets instead. But with Xcode 11, double-clicking a .crash file now opens Xcode instead of Console, and you can view the crash log in the context of a project. That’s very nice.

Continue reading …

Use Shared NSUserDefaults for XPC and Interface Builder Nibs

The default Interface Builder approach of using a “Shared User Defaults Controller” object breaks down if your app preferences are not stored in the standard place. Both my apps The Archive and the Word Counter for Mac are comprised of multiple executable applications. For The Archive, it’s the main app and the Quick Entry popup window. They share some settings, like which theme and font size is used. To share these settings, I rely on NSUserDefault (or just UserDefaults in Swift now). I cannot use the UserDefaults.standard, though, because that is tied to the currently running app’s bundle ID. In the case of the main app, it’s the ID of the main app; but for the Quick Entry helper – or any helper app –, it’s the helper’s bundle ID. This way, the defaults dictionaries are not shared.

Continue reading …

Put Test Files Next to Production Code for Better Discoverability?

The Kickstarter engineering team posted an interesting proposal: put your XCTestCase files into the same directory and group as your production code. Do keep the separate target ownership, of course.

One clear benefit is directory tree or file management, and discoverability of tests for people browsing the code: In most cases, you have FooService in FooProject/FooApp/FooService.swift, and FooServiceTests in FooProject/FooAppTests/FooServiceTests.swift. With nested folders, you need to navigate around even more. I got used to this Xcode default. But I also got annoyed by this split at the root level when I browsed code on GitHub. Multiple tabs in a modern browser to the rescue, this was never that problematic, given the test directory is structured in a similar way. If not, good look finding the file you’re looking for. (I hate that the RxSwift project, which I often had to browse to look up an implementation detail, has files that contain only a path reference to the real file, similar to ../../Core/SomethingSomething.swift, making tests pretty hard to find).

I will try this approach with a library module that I develop as a sub-project of The Archive and report back.

How to Create Fixture Files for Unit Tests

This is mostly a reminder for my future self: It doesn’t suffice to create a TXT file and add it to the target in the file inspector (⌘⌥1) to be able to read it as part of the bundle. You also have to drag it into the “Copy Bundle Resource” build phase of the target so it get, well, bundled into the product. (In my case, it was the test target.)

screenshot of Xcode
The .md file was part of the test target but loading it from the NSBundle failed until I added it to the proper Build Phase
  1. Create an empty file or add an existing file to the target’s group in Xcode and make it part of the proper target,
  2. drag it into “Copy Bundle Resources” build phase,
  3. load it using NSBundle(forClass: TheTestCase.self).URLForResource("filename", withExtension: "txt").

Storing PLIST or JSON files for structured data works just as well. I happen to require plain text flavors most of the time and always wonder why the loading fails for a couple of minutes.

Reusable View Components from Nibs

Just found this today in a Slack channel. It seems we can actually reference and re-use Xib files by overriding awakeFromCoder!

If we are loading from placeholder view, we create a real view and then we transfer some common properties from it and all it’s subviews, then we just return that instance in place of placeholder, otherwise we just return normal view (This method is implemented on NSObject so we can call super, but this still should be done with method swizzling instead of category smashing).

There’s a sample project on GitHub. Let’s tear it apart.

It works like this:

const int kNibReferencingTag = 616;

@implementation UIView (NibLoading)
// ...
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
  if (self.tag == kNibReferencingTag) {
    //! placeholder
    UIView *realView = [[self class] loadInstanceFromNib];
    realView.frame = self.frame;
    realView.alpha = self.alpha;
    realView.backgroundColor = self.backgroundColor;
    realView.autoresizingMask = self.autoresizingMask;
    realView.autoresizesSubviews = self.autoresizesSubviews;

    for (UIView *view in self.subviews) {
      [realView addSubview:view];
    return realView;
  return [super awakeAfterUsingCoder:aDecoder];

When the kNibReferencingTag is set, the current instance (self) is treated as a prototype. From that prototype we transfer common properties to the realView which is properly loaded from a Nib. That means it doesn’t go the kNibReferencingTag path but the usual path, deferring to super.

The sample app contains SomeView with its own Xib that should be reused.

In the app’s Xib, we have a scene that uses it as follows:

    <!--View Controller-->
    <scene sceneID="4">
            <viewController id="2" customClass="ViewController" sceneMemberID="viewController">
                <view key="view" contentMode="scaleToFill" id="5">
                    <rect key="frame" x="0.0" y="20" width="768" height="1004"/>
                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <view tag="616" contentMode="scaleToFill" id="VTu-Cz-9kE" customClass="SomeView">
                            <rect key="frame" x="113" y="216" width="100" height="100"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                        <view tag="616" contentMode="scaleToFill" id="7te-Q6-moz" customClass="SomeView">
                            <rect key="frame" x="199" y="446" width="100" height="100"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                        <view tag="616" contentMode="scaleToFill" id="7vx-xh-xRD" customClass="SomeView">
                            <rect key="frame" x="375" y="231" width="100" height="100"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
            <placeholder placeholderIdentifier="IBFirstResponder" id="3" sceneMemberID="firstResponder"/>

I know, Xib files aren’t the best to read. Here’s what it boils down to:

  • Create a scene using a view controller of type ViewController.
  • In its main view place 3 subviews …
    • of type SomeView,
    • all with the tag 616,
    • and a few standard color properties – apparently all set to white. It doesn’t matter anyway since the SomeView.xib will dictate what it really looks like.

Unlike @IBDesignable components, you won’t have any live preview in Interface Builder. Just empty placeholder boxes.

iRamDisk May Speed Up Your Xcode Compilation Times

Teaser image

I code on a late 2011 Mac Mini with 8 GB RAM and a 256 GB SSD. This machine is a ton faster than my old MacBook Air was. Compilation still takes time, but it seems that iRamDisk helps a bit.

Lately I wondered if I could cut down the 30s compilation time (3mins with a clean build folder) if I had a Mac Pro, or MacBook Pro, or iMac, or whatever next tier device. Faster cores, more cores, doesn’t matter. But buying a Mac for $3k is out of question at the moment. So I’ve been looking for other tricks.

The only thing that’s faster than a SSD is RAM. That’s when I found the app iRamDisk. It offers an option to move the derived data folder to a virtual disk in RAM. It seems I can reduce the clean build time from 3mins to 2mins with that. Xcode needs about 1.5GB derived data for the Word Counter – at least that’s how big I had to make the RAM disk to not get filled quickly. The overall memory pressure is a bit higher, the Mac is using swap more, but compilation becomes faster at last.

There’s a downside, too: after every reboot the RAM disk is empty, so Xcode has to index the project again and compile fresh at least once a day. Depending on your usage this can be annoying or not be a problem at all.

You can download a trial from the website or buy it for $19.99 on the Mac App Store.

Don't Build on El Capitan Without Checking App Transport Security

I got burned this week. Pretty bad. I shipped a small bugfix release for my Mac app Word Counter a couple of days ago to prepare for the “big one” coming this week. Naturally, I built that version on my El Capitan dev machine. I pushed the update to my server. Updates using Sparkle worked. – But now users of that version cannot ever update to the next version. Because I haven’t thought about ATS.

Continue reading …

Make Custom Debug Build Configurations Play Nicely With CocoaPods

To test the Word Counter during development, I have long used a special build target. But that doesn’t scale well if all I want is change a preprocessor macro to switch from file-based to in memory storage, for example. I’ve never played around with build configurations in Xcode. They work well with Schemes, though, and setting up a build configuration and a scheme is much less overhead than maintaining a custom target.

Continue reading …