Ownership and +1s

Yesterday, hell froze over.

Many people have written about the change in Apple’s external engineering culture. With the announcement of Swift at WWDC 2014, Apple seemed to have relaxed its notoriously tight-lipped communications: Chris Lattner is candidly answering questions in the developer forums, there’s a Swift development blog and I’ve even had a radar resolved! While matters are definitely changing for the better, a company of Apple’s size has insane inertia and good things take time.

So it comes to little surprise that, when ResearchKit was announced as an Open Source project, many members of the community were skeptical. But where the “old” Apple would have handed a zip archive to registered Apple Developers and called it a day, the new Apple now has a GitHub account.

A GitHub account. Apple.

I don’t think anybody would have imagined this two years ago (cue the never happened under Steve) but there’s even more: the ResearchKit team have expressed interest in adding a podspec for official CocoaPods support.

I’m glad they understand that in order for ResearchKit to succeed, they need to get it as many developers’ hands as possible and CocoaPods has done a lot to lower the barrier to entry for using third party dependencies.

However, if Apple can step up their Open Source game, we can too.

The Pull Request to add the aforementioned podspec file quickly filled with πŸ‘s. While I understand that those emoji were well intended and only meant to express support to the cause–hey, it beats duping a radar–the thread got very noisy very quickly. As someone who maintains some Open Source repos myself, it pained me to see that the ResearchKit team’s first foray into the public iOS community was met with such clutter.

Again, I’m sure that those πŸ‘s had only the community’s best interests in mind, but I think there is a certain sense of entitlement in our part of the Open Source world when it comes to support for some random iOS version, the dependency manager of the day or fixes for arbitrary crashes in your app, which may or may not be related to the project in question.

Let me tell you, nobody likes to maintain iOS 7 support in their spare time.

Bumping or πŸ‘ing that issue for the twentieth time is probably not going to do anybody much good. The thread becomes harder to follow for everybody and the maintainers get more email at best and a sense of guilt at worst.

Open Source projects rarely come with a Service Level Agreement. There are many reasons to pursue Open Source just as there are many other interesting things in life. Look at the list of contributors to your favorite OSS project and imagine what would happen if they all pulled a __why, as they have every right to.

If you decide to incorporate someones project into your app, especially if you write said app as part of your day job, you have to be willing to support that project when the poop emoji hits the fan. That can mean using your own time and engineering resources or financially supporting said contributors. I don’t think many people would balk at the opportunity to get paid for working on something they started out of their own curiosity.

But maybe money is tight and you don’t have the knowledge necessary to support every project. That’s cool. If you don’t think you have the skills to fix a problem yourself, try regardless. A Pull Request will always get you further than an Issue. Even if it breaks the build, it shows that you value the maintainers’ time highly enough to match it with some of your own. It’s also a great opportunity to familiarize yourself with a code base and learn a thing or two.

Update: Thanks to Ayaka and Orta for their Pull Requests on this post πŸ’›.

Posted Apr 15, 2015 in thinking-about

Beyond UXKit

Yesterday, Apple seeded the beta version of 10.10.3 to developers. It contained the long-awaited Photos app, an overdue successor to iPhoto. It also contained, however, a much more unexpected surprise. When poking around the app’s internals, Jonathan Willing came across a new internal framework, he wrote:

The new Photos for Mac is based on a new private framework in 10.10.3, UXKit. It is essentially a replica of UIKit, based on top of AppKit.

It includes favorites such as UXView, UXNavigationController, UXControl, UXCollectionView, UXTableView, UXLabel, UXImageView, and much more.

Since UIKit was built with years of experience of AppKit being in production, many consider its APIs superior to AppKit’s. Bringing those interfaces over to OS X would make it easier to switch between the two platforms and even allow for cross platform code where the interaction patterns permit it.

This got a lot of people pretty excited.

Now, we don’t know if UXKit is more than just a convenient shim built by the Photos team and if it will ever become a public framework, but even if it will, it won’t be enough.

UXKit is not a leap forwards, it is at best a sidewards step over the platform gap. The whole paradigm of stateful UI components being whipped into shape on the main thread is broken beyond repair.

- (void)userDidLogIn:(NSNotification *)notification {
    [self updateAllTheViews]; // You better be on the main thread.
}

It’s 2015 and you can’t even layout an off-screen view when you’re not on the main thread. We need something better.

React and beyond

Facebook recently announced React Native, the iOS and Android extension to their existing React JavaScript framework for building data-driven UIs in the browser. A lot of people reacted (ha) like this:

Ewww, JavaScript.

– Too many people

I’m floored that the same community that complains that 40-year old language features like generics needlessly complicate their precious Objective-Blub would get their collective nose all up in the air about JavaScript this way.
As Josh Abernathy put it, JavaScript is an implementation detail.

A couple years back, the same smugness of platform superiority hung around when Facebook ditched their HTML5 based app (rightfully) for a native implementation. Little did we know that there would be a lot to learn from the DOM-slingers.

See, I don’t know or care if React Native will be what we all write our apps in two years down the road, but this is not about HTML, it’s not about CSS and it sure as hell ain’t about JavaScript.

It’s about expressing your application’s user interface as a function of this signature:

public func updateUI(state: State) -> RootView

A pure function like that doesn’t need to care what thread it layouts your views on. Imagine being able to layout all your table-view cells in parallel. (Facebook’s AsyncDisplayKit demonstrates some of the performance gains that can be made by offloading UI calculations to the background.)

An inert representation of your entire view hierarchy is also much easier to persist than an a tree of UIViews. When was the last time you implemented -[UXView initWithCoder:]? Imagine iOS simply restoring the last view hierarchy on app start.

Similarly, such a serialization format could be written directly. I’m not the world’s biggest fan of JavaScript, but I’d prefer merging a JSX file over a nib file any day of the week.

If it is completely encapsulated, hot-swapping your layout code suddenly becomes feasible. Every modern browser ships developer tools that beat Interface Inspector and Reveal single-handedly. Imagine being able to attach Interface Builder to your running app, restructuring it on the fly while all data is being preserved.

And that’s only the beginning. Even impressive touch interactions can be described in only a few lines of declarative constraints.

Only Apple can do this

There’s been a lot of talk in the previous months about the perceived decline in Apple’s software quality. While I don’t doubt that a lot of excellent work is being done inside Apple, from the outside it’s still a black space-gray box.
I just hope that somewhere inside that box, a true successor to UIKit is being built, something that will take us to the iPhone 12S and beyond.

We can’t reap the full benefits of Swift’s powerful language features if we’re being constrained by UIViewController in its current form. We won’t easily maintain a smooth 60 fps if even basic layouting is shackled to the main thread. We need to pop our filter bubbles and steal the best ideas from Android, the Web and 1973.

I’m no longer fully sure that the future of iOS UI engineering will come out of Cupertino, but I’d love to be proven wrong in June.

Posted Feb 6, 2015 in thinking-about

VoiceOver Quick Navigation

I’ve maintained for a long time that great apps should have great accessibility support, but today I learned of another reason that might also be of particular interest to developers.

If you don’t know, VoiceOver is the name of Apple’s accessibility technology to help users with visual or motor impairments use their iPhones. It’s most well-known for its screen reader capabilities, but it also supports controlling your iPhone or iPad entirely with the keyboard.

This is great to avoid reaching over to your phone all the time, and it’s also much easier to enter your test account’s password on a physical keyboard.

Setup

First, connect a Bluetooth Keyboard to your phone. I use the amazing 1Keyboard to share my computer’s keyboard with my iPhone with the touch of a button.

Next, enable VoiceOver. On iOS 7, you’ll find it under the Accessibility entry under General in your Settings app. I also recommend adding VoiceOver to the Accessibility Shortcut menu for convenient access to by triple-clicking the Home Button1.

VoiceOver allows you navigate through the visible items both by dragging your finger across the screen and by swiping left and right over the screen.

Only that, instead of swiping, you can now use your keyboards arrow keys.

Make sure to have Quick Nav enabled by pressing ← β†’ (The left and right arrow keys) in quick succession. While Quick Nav is enabled, you can iterate over all accessibility items on the screen using ← and β†’. Quick Nav makes using VoiceOver with a keyboard much easier and the rest of the article assumes you have it running.

Press any of βŒ₯↑, βŒ₯↓, βŒ₯←, or βŒ₯β†’ to scroll the currently active scroll view.

Use βŽ‹ (Escape) to leave the current screen, that is, to quickly select and tap the back button.

Interaction

To interact with a selected element, press ↑ and ↓ in quick succession. When you’re not using the keyboard, you can double-tap anywhere on the screen for the same effect.

Adjusting sliders, page controls or steppers however requires a different key command.

Navigate to the element you want to interact with and select Adjust Value in the Rotor by pressing ↑ and then one of ← or β†’.

The Rotor is a secondary menu that allows you to chose what happens if you press ↑ or ↓ or swipe up or down on the screen. Once you set it to Adjust Value, you’ll be able to use ↑ or ↓ down to adjust values.

There are a couple of other useful settings for the Rotor, such as Vertical Navigation that can be enabled in the Rotor menu in the VoiceOver settings.

Advanced shortcuts

Unfortunately, most of the VoiceOver keyboard commands use the awkward combination of the Control and Options keys. If someone knows a way to map that to something easier to reach, such as Caps Lock, please let me know!

To press the Home Button, press βŒƒβŒ₯H. If you have good eye-sight or share and office with co-workers, press βŒƒβŒ₯S to mute or unmute VoiceOver.

To quickly change VoiceOver settings, such as Speech Rate or Typing Echo, select a setting using βŒƒβŒ₯βŒ˜β† or βŒƒβŒ₯βŒ˜β†’ and change the selecting settings with βŒƒβŒ₯βŒ˜β†‘ or βŒƒβŒ₯βŒ˜β†“.

For reference, here’s a complete list of all the keyboard shortcuts supported by VoiceOver:

VoiceOver keyboard commands

Turn on VoiceOver help βŒƒβŒ₯K
Turn off VoiceOver help βŽ‹
Select the next or previous item βŒƒβŒ₯β†’ or βŒƒβŒ₯←
Double-tap to activate the selected item βŒƒβŒ₯Space
Press the Home button βŒƒβŒ₯H
Move to the status bar βŒƒβŒ₯M
Read from the current position βŒƒβŒ₯A
Read from the top βŒƒβŒ₯B
Mute or unmute VoiceOver βŒƒβŒ₯S
Open Notification Center FnβŒƒβŒ₯↑
Open Control Center FnβŒƒβŒ₯↓
Open the Item Chooser βŒƒβŒ₯I
Double-tap with two fingers (usually toggles playback) βŒƒβŒ₯-
Adjust the rotor See Quick Nav
Swipe up or down βŒƒβŒ₯↑ or βŒƒβŒ₯↓
Adjust the speech rotor βŒƒβŒ₯βŒ˜β† or βŒƒβŒ₯βŒ˜β†’
Adjust the setting specified by the speech rotor βŒƒβŒ₯βŒ˜β†‘ or βŒƒβŒ₯βŒ˜β†“
Turn the screen curtain on or off βŒƒβŒ₯⇧S
Return to the previous screen βŽ‹

Quick Nav keyboard commands

Turn on Quick Nav to control VoiceOver using the arrow keys.

Turn Quick Nav on or off ← β†’
Select the next or previous item β†’ or ←
Select the next or previous item specified by the rotor ↑ or ↓
Select the first or last item βŒƒβ†‘ or βŒƒβ†“
Double-tap to activate the selected item ↑ ↓
Scroll up, down, left, or right βŒ₯↑, βŒ₯↓, βŒ₯←, or βŒ₯β†’
Adjust the rotor ↑ ← or ↑ β†’

I hope that this neat trick helps you avoid some arm strain from repeatedly reaching over to your phones. If you’d like to read more about accessibility, check out sessions 200 & 202 from this year’s WWDC.

  1. You may also want to enable Invert Colors for reading in bed, while you're at it.
Posted Oct 7, 2013 in thinking-about

Overloading C Functions with Clang

Clang, LLVM’s compiler front-end for C-based languages, features a couple of interesting language extensions to C, C++ and Objective-C. You are probably familiar with auto-synthesis of properties or the new subscripting syntax.

One of the lesser known extensions, however, is the __attribute__((overloadable)) annotation.

While languages like Java and C++ allow you to define multiple functions with the same name but different arguments, this feature has been absent from C.

However, using recent versions of Clang you can now rectify this behavior and since Objective-C is a superset of C, knowing how to use this feature can be useful even if you rarely venture outside of Cocoa or Cocoa Touch.

Consider for example these function declarations:

#define OVERLOADABLE __attribute__((overloadable))

OVERLOADABLE NSArray *map(NSArray *array, id(^)(id obj));
OVERLOADABLE NSDictionary *map(NSDictionary *dictionary, id(^)(id key, id obj));

We declare two different versions of the classic map function.
Instances of NSArray will have a block applied to their elements that takes a single argument while instances of NSDictionary have both their keys and values sent to the block.

The compiler will figure out which map it needs to call simply based on the types of the arguments.

The implementation is pretty straightforward, too:
-[NSArray enumerateObjectsUsingBlock:] is used to iterate over all elements. If the block passed to map returns nil, the element is discarded.

OVERLOADABLE NSArray *map(NSArray *array, id(^block)(id))
{
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:array.count];

    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        id mapped = block(array);

        if (mapped) [result addObject:mapped];
    }];

    return result;
}

You may want to consider writing a parallel version of map that makes use of -[NSArray enumerateObjectsWithOptions:usingBlock:] and passes in NSEnumerationConcurrent.

The implementation for dictionaries looks similar:

OVERLOADABLE NSDictionary *map(NSDictionary *dict, id(^block)(id, id))
{
    NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:dict.count];

    [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        id mapped = block(key, obj);

        if (mapped) result[key] = mapped;
    }];

    return result;
}

Now we have a nice and clean way to map over Cocoa’s most prevalent data structures:

NSArray *numbers = @[ @1, @2, @3, @4 ];

NSArray *doubled = map(numbers, ^NSNumber *(NSNumber *number) {
    return @(2 * number.doubleValue);
});

NSDictionary *user = @{
  @"username": @"robb",
  @"website": @"http://robb.is"
};

// Implementing 'each' and its concurrent equivalent
// is left as an exercise to the reader.
each(user, ^(NSString *key, id obj) {
    NSLog(@"%@: %@", key, obj);
});

I think function overloading is a welcome addition to C and it goes to show how knowing the underpinnings of Objective-C can help you write better and more concise code.

Update: Nick Lockwood raised the point that map may be better suited for a category. When I came up with this example, I was also considering an each implementation that could deal with id<NSFastEnumeration>. E.g.:

OVERLOADABLE void each(id<NSFastEnumeration> list, void(^)(id obj));
OVERLOADABLE void each(NSArray *array, void(^)(id obj));
OVERLOADABLE void each(NSDictionary *dict, void(^)(id key, id obj));

That being said, if you’re looking for a solid and well tested map category, check out BlocksKit.

Posted Jan 1, 2013 in thinking-about