Archive for July, 2014

Icons: Fathomable and unfathomable

Screen Shot 2014-07-18 at 3.16.03 PM

From left to right you have: File, Quick Help, Identity, Attribute, Size, Connections, Bindings, and View Effects. While it’s not as if you can’t figure the new icons out by position and general shape, I’m left a little bewildered as to the design intent for this update.

  • The file inspector is apparently supposed to look like a folded edge document, it ends up looking like a cranky superhero with a big chin and no forehead. C-
  • I don’t have any big beef with the help icon but it’s ugly. The smooth light gray and pixelated dark gray doesn’t work for me. B-
  • What’s supposed to look like an ID or drivers license ends up saying “newspaper” instead of “identity”.  D
  • I’ve served with toolbelts. I knew toolbelts. Toolbelts have been friends of mine. And Attributes Icon, you’re no toolbelt. Can also be mistaken for hipster with strange ears, bad facial hair. F.
  • Again, I get this is a ruler. It’s just not a good ruler. Not the worst of the icons, but looks more like a comb than a ruler. C.
  • Connection icon. Ugly with pixelation but it works. B+
  • Oh for crying out loud. We are not lab rats, Apple. Bindings? F
  • The view effects icon works better for me as an “identity card” than the identity icon but that still doesn’t make it good. C+ because of the layered “effect” that kind of sort of barely makes the mark.

Beta: Apps and Traits, some thoughts

The iOS family continues to grow. Although iOS targets are not nearly as splintered as Android’s multitude, iOS apps must adapt interfaces to numerous configurations for universal deployment. Routines specific to iPads or iPhones, to landscape or portrait orientation, and to retina or non-retina screens have transformed many iOS apps into a tangle of special-purpose code.

To push back, iOS 6 introduced Auto Layout, a descriptive system for interface design. Auto Layout enabled developers to use rule-based view placement that automatically adjusts to screen dimensions and orientation.

Now iOS 8 adds the notion of adaptive deployment. New classes and protocols enable apps to retrieve the specifics of the current runtime environment. This enables them to adapt not only to hardware limitations but also to whatever screen space has been allocated to their presentations. A truly adaptive app gracefully responds with a well designed and engaging interface, ready for the user at any size.

A iOS 8 trait collection describes a single point in deployment space. This space represents the range of possible conditions an interface might encounter in the real world. By making these traits concrete, Apple enters into a somewhat implicit contract with the developer – these are the types and ranges of flexibility you must design for.

Even if Apple introduces multi-windowing, you only have to worry about “compact” and “regular” interface sizes under the current system. There’s a (vague and legally unenforcable) guarantee that for at least the next year Apple will not add some “Ultra Compact” game-changer where you suddenly have to worry about designing forms for 100-pixel destinations. And, if Apple does introduce that windowing, the traitCollectionDidChange callback means you can switch your tablet presentations to phone ones for side-by-side execution and then back again.

No matter what kind of apps you design, a tension always exists between pixel-perfect control and adaptability. An interface that looks stunning on a 4″ iPhone may look cramped on a 3.5″ screen and sparse on a tablet. This has led some developers to build what is essentially multiple codebases under a single app umbrella.

With trait collections and standardized callbacks, iOS 8 is attempting to bring sanity back to those apps. So long as the presentation specifics don’t get too ridiculous, Auto Layout and trait-driven assets should be able to handle those specifics both at launch time and during run time.

Will Apple introduce a 3x display resolution? I think it unlikely but if they do, the technology is already in-place to handle that trait collection with a 3.0 display scale. Will Apple add a new geometry to the phone family? That’s a rumor that seems to have more appeal — but Auto Layout is ready for that, and the compact-regular layout traits will support any baby-dolphin-sized phablet that might hit the market. Will iOS 8 support multi-app display? The technology to support it is ready for developers if they take advantage of those features.

I admit that some of Apple’s design choices for trait collections baffle me. For example, how is it that a 480-point height is “regular” and a 586-point width is “compact”? But despite that, I find it comforting to  receive a concrete set of interface expectations via the trait API.

What do you think? Please do let me know.

Beta: Auto Layout Constraint Activation

I’m pretty excited about the new active constraint property. To date, a lot of my work involves adding and removing constraints. Now with activateConstraints: and deactivateConstraints: you can enable and disable constraint groups all at once. I can see this being used in a variety of ways:

  • Disabling constraints for dynamic animators — you don’t have to layout and then remove items
  • Choosing constraint sets for various states — you can use one set for example when a view is visibly presented and another if it is hidden or create closed and open presentations.
  • Bringing individual constraints on-line or off-line that have competing priorities, so you can disable rather than remove a higher-priority item until it is needed again.

I’m not sure if this is animatable so I have to test that bit, but I’m really hoping it is.

One final note: the two activator/deactivator methods are documented to be more efficient than accessing constraints one-by-one.

UPDATE: WHOA! Self-installing constraints! Finally!

UIView *v = [UIView new];

v.autoLayoutEnabled = YES;

[self.view addSubview:v];

NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];

NSLog(@”%@”, self.view.constraints);

c.active = YES;

NSLog(@”%@”, self.view.constraints);

2014-07-11 16:44:09.138 Hello World[18020:1138706] (

)

2014-07-11 16:44:09.141 Hello World[18020:1138706] (

    “<NSLayoutConstraint:0x7fed2d809090 UIView:0x7fed2d9449b0.centerX == UIView:0x7fed2d93da70.centerX>”

)

 

Beta: Coordinate spaces

New in beta 3, coordinate spaces are a UIScreen property. There’s a UICoordinateSpace protocol for UIViews and APIs to support point conversion, presumably for split-screen app development.

UIScreen.h

Added UIScreen.coordinateSpace
Added
UIScreen.fixedCoordinateSpace

UIView.h

Added UICoordinateSpace
Added UICoordinateSpace.bounds
Added -[UICoordinateSpace convertPoint:fromCoordinateSpace:]
Added
-[UICoordinateSpace convertPoint:toCoordinateSpace:]
Added -[UICoordinateSpace convertRect:fromCoordinateSpace:]
Added -[UICoordinateSpace convertRect:toCoordinateSpace:]

 

Swift: Adding multiple-index array access

This morning, #swift-lang buzzed about multiple subscripts. “zOMG, you can have subscripts take more than one argument?” Why yes, yes you can. It’s a neat Swift trick, but a (pardon me) a tricky one.

For example, you might create an array and want to index it with foo[3, 5] or foo[7, 9]. Turns out that the general case is slightly trickier than I anticipated. The following demonstrates the desired indexing behavior.

let foo = [1, 2, 3, 4, 5, 6, 7]
println(foo[2]) // prints 3
println(foo[2, 4]) // prints [3, 5]
println(foo[2, 4, 1]) // prints [3, 5, 2]
println(foo[2, 4, 1, 5]) // prints [3, 5, 2, 6]

However, you don’t get this behavior out of the box.

Screen Shot 2014-07-10 at 11.47.55

Backtracking a little, you can easily build a custom subscript when you know a priori the number of elements you’re aiming for. For example, this extension returns two index items at a time. This is easy to implement and Swift can easily use parameter matching to figure out the overloaded results you’re aiming for.

// Two at a time
extension Array {
    typealias ArrayType = Element
    subscript(i1: Int, i2:Int) -> [ArrayType] {
        return [self[i1], self[i2]]
    }
}

It’s harder to extend this behavior for an arbitrary number of arguments. Specifically, you must take care with variadic arguments. The following approach won’t work.

subscript(i1: Int, i2:Int...)

Use that approach and you end up with infinite loops. That’s because Swift cannot distinguish this parameter declaration from an override of the standard single-item indexing. Variadic parameters accept zero or more values of a specified type, so  [2], [2, 4], [2, 4, 6], and [2,4, 6, 8] all match this declaration.

(Int, Int…) is virtually identical to (Int) at runtime, so Swift chooses this override to the original implementation for single-parameter lookups. That’s where the infinite loops come from. To make this work, you need a signature that won’t confuse swift. The proper solution uses two non-variadic arguments followed by a third variadic one, creating a “use this implementation for two or more parameters” scenario.

The following extension provides a final working solution. When you provide at least two subscript arguments, Swift knows to use this subscripting implementation.

extension Array {
    typealias ArrayType = Element
    subscript(i1: Int, i2: Int, rest: Int...) ->  [ArrayType] {
        var result = [self[i1], self[i2]]
            for index in rest {
                result += self[index]
            }
            return result
    }
}

 

Swift: Coping with bad enum typedefs

Earlier this evening, a member of #iphonedev on Freenode needed to use the following function:

func rangeEnclosingPosition(_ position: UITextPosition!,
            withGranularity granularity: UITextGranularity,
                inDirection direction: UITextDirection) -> UITextRange!

The docs say that UITextDirection “can be of type UITextStorageDirection or UITextLayoutDirection.” but when you look this all up, you get:

enum UITextStorageDirection : Int {
    case Forward
    case Backward
}

enum UITextLayoutDirection : Int {
    case Right
    case Left
    case Up
    case Down
}

typealias UITextDirection = Int

As one member of the #swift-lang room put it, “‘My fault or Swift’s fault’ is a pretty frustrating experience.”

What to do? Lily B was able to suggest an immediate workaround by using UITextStorageDirection.Forward.toRaw(), and encouraged filing a radar.

Bigger lesson, especially taking yesterday’s language updates into account: Don’t write production code in a beta language, and make copious notes where you used work-arounds so you can re-address them later.

Swift: Unicode philosophy

Today over at #swift-lang, a lively debate ensued over a hypothetical. What if Swift added arbitrary infix operators including Unicode. Would development be better served with operators like  the intersection operator (“∩”) over the current camelCode approach?

Some advantages are self evident. ∩ is a standard, mathematical representation. It’s widely accepted, widely used, and you’ll encounter it in most math textbooks. Plus it’s generic. It avoids mentioning a specific collection type, which would be required for selectors.

Despite this, I found myself arguing against (or at least against the overuse of) generic Unicode operators. While I welcome Unicode support in Swift, I see it best used to enable native language development. Unicode creates localized variables that make better sense than forced anglicizations. (Admittedly, I don’t see the point of cute dog-cow variables that show off language capabilities rather than enhance day-to-day development.) Even though this  operator is a decided win in the specific merits, I felt Unicode operators failed in the more general case.

I still experience occasional APL flashback nightmares.  The language wasn’t just a horrible experience in tracking down the right characters to create code. Once written, it was  virtually unintelligible even to those who had created those routines. Having experienced write-only code in the classroom, I’m not eager to return there in the app store.

Using Unicode operators incurs costs. As ∩ is not part of the standard first-level keyboard access, there’s a creation cost — both the mental overhead of remembering the operator to use as well as the hunt to find the character to enter.

Second, there’s a cost to readability from a cognitive recall/recognition standpoint. I admit the cost here is small since this particular operator is so well defined mathematically. But recognizing “intersectionWithSet” surely will map better to some people than recalling what the ∩ operator does, even if you end up having to create a suite of specialized selectors. This example really depends on the individual’s training. As operators become more self-defined or esoteric, this cost will rise.

Third, there’s a symbolic representation cost. Outside of standard mathematical representations, there’s an organizational overhead involved in choosing and managing representation elements that camel case text avoids. While the intersection operator is well defined, more general operators won’t be. (One shudders at the possibilities of the “Pile of Poo” operator — except perhaps for release calls.)

Finally, there are sharing costs. Any non-ascii code places a burden on documentation and web sites, especially those that don’t offer copy-paste support. You might be especially proficient with &amp; and similar, but not everyone in your organization will be

It’s not that these costs are unreasonable or that some operators aren’t natural fits, it’s that I’m not sure the benefits outweigh those costs when implemented as a whole. While I can argue the other way (put it into the hands of developers who surely will use this parsimoniously and appropriately), I find myself preferring the more textual solution even if both are available.

Swift: The new half-range operator

In Xcode beta 3, Swift’s half-closed range operator has changed from .. to ..<, adding a less-than-sign visually distinguish half ranges (up to but not including) from full ones (up to and including). The update enhances visual inspection, making a clear differentiation between half (..<) and full (…) ranges.

While I applaud the intent, I dislike the result.

I get how errors similar to those between assignment and equality operators (= and ==) might happen. But while the =/== operators act in distinct ways, the range operators are more closely related. They’re less likely to produce foundational mistakes, and easier to catch through normal inspection.

A few additional points:

  • The new half range operator is ugly. It turns an elegant for i in 1..5 into a visually confusing 1..<5
  • When used next to a 3-digit, it looks like ascii art: for i in 1..<3 println(“Love you!”)
  • Even without 3-adjacency, the new operator looks like an upside down deranged duck ..<
  • The new operator requires explicit escaping on the web. (Thanks Andrew Wagner)

I’ve filed a radar. If you feel the same, consider adding one too.

As a final note, while this language tweak looks a bit like a literal duck, some are comparing it to the Coding Horror metaphorical one.

Swift: my love for postfix printing

You may have noticed that, to date, Swift playgrounds are not the most stable. (You may add jokes here about the San Andreas Fault and your ex-significant-others.)  I often find myself copying items to command-line projects for testing.

Playgrounds offer the built-in results gutter to help determine when classes, structs, and functions are built and testing properly. With a command-line app, print statements replace single item evaluations. I prefer to do so in a way that doesn’t require tedious edits. Enter the postfix print operator.

operator postfix *** {}
@postfix func *** <T:Printable>(object : T) -> T {
    println(object.description)
    return object
}

What this operator gets me is something that I can easily use to convert items to print statements without editing to both the left and right. I can replace

myValue

with

myValue***

It also enables me to use a global find and replace to comment out the prints, replacing them with a sandbox-style declaration.

myValue //***

Nearly everyone I’ve shown this to reacts with noticeable horror, but I rather like its utility.