• We Got One

    tfw you book a freelancing gig

  • Watch notifications are apps

    A widely circulated NYTimes article, citing lack of support from Facebook and Snapchat as primary examples, reports on the wait-and-see approach many big mobile app developers are taking to Apple Watch. During Gruber’s recent appearance on The Dalrymple Report, the pair are generally dismissive of the piece and make the argument that one shouldn’t to expect apps that work well in a phone form factor to work well on a watch. They then go on to praise Apple Watch’s notifications as a major use case. Presumably they appreciate notifications from third party apps, so I think it’s interesting to note that watchOS apps are the mechanism by which developers can provide custom notifications.

    In Apple parlance these are called Long Look notifications. These long look notifications are essentially fully featured in terms of what they can present. Basically, if a watch app can render something, a notification can render it too. While they lack full interactivity, apps can provide custom action that are presented as buttons under the content. What’s interesting about these is that the iOS watch extension (or native app in watchOS 2) is running while the notification is onscreen. This means that the notification can perform things like network requests or async asset rendering. So a photo app can show a photo, or a scheduling app could fetch estimated travel time from a server. I’d argue that for most applications (especially anything push-centric like a messaging app), the notification portion of the watchOS app is the most important thing to focus on.

  • Thoughts on Apple Music (and why I'm switching back to Spotify)

    After a wave of excitement around the release Apple Music, the shine is wearing off. Jim Dalrymple publicly and dramatically declared the service a “nightmare” for losing the majority of his music. After a trip to Apple HQ for reeducation technical support, Dalrymple got his precious Metallica back and is seemingly again using the service1. Marco weighed in, taking aim at the punching bag that is the bloating iTunes’ feature set, the unreliability of the iTunes backend2, and coming to the conclusion that the safe approach is to keep Apple Music away from existing music libraries.

    Personally, I was eager to hop on the Apple Music train. I’ve disliked some of Spotify’s recent UI decisions and was ready for something fresh and different. I’ve been using Apple Music since day one and have used it nearly exclusively since. I haven’t experienced any massive data loss or other nightmare scenario, but I’m switching back to Spotify because Apple Music just isn’t very good, and despite its flaws, Spotify is better for the way I listen to music.

    On the surface, both services offer essentially the same value proposition. Tens of millions of tracks on demand is table stakes at this point in the streaming music game. Apple Music does have deep integration with existing iTunes libraries, but that is becoming a legacy feature as the vastness of those streaming libraries continues to swell. I haven’t bought a physical CD in years, I don’t buy things on iTunes anymore, and I even let my private music torrent tracker accounts lapse. I only stream music now. Way of the future.3

    The main problem I have with Apple Music is that it isn’t very good at surfacing new and interesting music. Despite their best attempts to bury it4, Spotify’s Discover feature is really good at suggesting relevant music. It smartly uses recent listening as a cue for suggestions, so if I get hooked on an album I’ll get a “similar to” listing in my recommendations. I just today played the first two suggested albums and both were a) bands I’d never heard of and b) good. It’s not always perfect, but it’s usually something interesting. Based on the quality of suggestions Spotify gives, I don’t have the aversion to algorithmic recommendations that Apple Music bases its whole philosophy on.

    By making the For You tab the default screen, Apple Music thankfully puts their recommendation feature front and center. I spent a lot of time attempting to train Apple Music to my tastes, spending at least a few hours hearting a bunch of albums hoping to tune its sense of my tastes5. However, in Apple Music these recommendations are frequently other albums by the same bands (and even dumber, sometimes the album that was hearted in the first place) or other projects of its members. Imagine an interaction with a record store clerk that went like this…

    Oh you like Panda Bear? Have you heard of Animal Collective??

    You hearted the Radiohead b-sides playlist and have every album of theirs in your library? Give Intro to Radiohead a listen!

    You told me you're into At the Drive In's Relationship of Command and I've got a great new suggestion for you: At the Drive In's Relationship of Command.

    I’d pull a skokie and slowly back away.

    So, with For You not giving me album recommendations like I’m used to, I started trying to get into a groove of listening to Apple Music’s vaunted editor curated playlists. They usually take the form of Intro to…, Deep Cuts of …, Influenced by…, Influencers of… some artist. While they can surface some interesting stuff they’re somewhat repetitive in content (hint: every rock band was influenced by Brian Eno). But perhaps I could find songs I like, which would lead me to artists and albums I like. So I start listening, hear a song I dig, try to view the artist page, and then get this every damn time…

    Unknown Artist

    Fuck. Ok. So I manually search for the band, like an animal, and now want to dive in some more, like maybe explore some related artists. After finding the (hidden, terribly formatted) artist bio / similar artists screen I realize that the similar artists aren’t tappable and half the names get clipped so even manually searching for those can be a pain too. It doesn’t seem conscious, but Apple Music is constantly reinforcing one’s specific preexisting tastes in music. That’s great for those who think only the music made while they were young and beautiful is worth listening to, but for someone who is constantly looking for something new, exploring in Apple Music can feel like a chore.

    Spotify laps Apple Music on the technical merits as well. I can seamlessly handoff listening to a track between the iPhone and Mac clients, it always remembers where I was between sessions, and I can even use the controls in the Mac client to drive the iPhone client while it’s playing in my pocket. Apple Music, made by the inventors of Handoff, supports none of these features. Spotify also has noticeably faster start times for tracks and that cool hold a finger down on an album to get a quick preview feature.

    At this point I’m basically done unless Apple Music can differentiate itself somehow. Beats One is certainly a unique offering, but in my hours of listening to it I’ve come to quite dislike their programming. Beats One head Zane Lowe likes to tout that the station’s “genre is great”, but to my ears their genre is pop. Varieties of pop (including a fair share of hip hop), but it’s always hype music and nearly always pop. Beats One promised a break from the trend of corporate mandated playlists, but in the first day on air I heard a new, Apple Music exclusive track by Apple Watch promoting Pharrell Williams at least four times. Coincidence? Perhaps.. Pharrell does fall into their pop-centric sound quite neatly. In the end though, I don’t want to feel like I’m hanging out inside of a Uniqlo all day, and Beats One isn’t for me.6

    Apple Music’s other differentiating feature is Connect, which promises to be a way to get behind the scenes and interesting content from followed artists. I follow more than 20 artists on Connect in addition to some of Apple’s curation teams and only one post in my feed is from someone not on Apple’s payroll, and that is simply a new track notification, not something made for Connect. It’s too early to tell, but unless Apple can get some artist buy-in Connect seems DOA.

    Being preinstalled on every Mac and iOS device is almost certain to give Apple Music a good subscriber base, but it is far from the offering best experience of any streaming service out there, which is what we Apple fans value above all else. Apple Music can and will improve, and I’ll certainly keep my eye on changes. But a side effect of tying Apple Music to iOS and iTunes releases is that it’s going to be iterated upon much less frequently than Spotify. Starting a race late and then running slower than the competition is rarely a winning strategy.

    1. Which prompted a hilarious retraction of a segment of his podcast, which no doubt contained some choice language directed at Apple Music.

    2. One word: WebObjects.

    3. Way of the future.

    4. Hamburger Menu > Music > Discover

    5. Another nitpick: I created a playlist of these “Loved” songs using the smart playlists feature in iTunes. This playlist definitely does not contain all my loved tracks.

    6. Not everything on Beats One is all bad. Giving RTJ a show is cool and the format for the St. Vincent show is very clever.

  • Xcode 7 is a game changer...

    Unlock

    Xcode will now wait for a device to unlock before running a build instead of just bailing. This is small but fantastic news.

  • Swift selectors suck
    (but they can be better)

    Swift language features must attempt to satisfy two sometimes contradictory objectives: they must explicitly maintain the safety of the type system while also providing a concise, developer friendly syntax. Swift’s approach to ensuring safe code via static analysis is deeply embedded into it’s design and idioms. But by their nature, safety features like type checking and optionals can result in more verbose code than willy-nilly Objective-C or other dynamically typed languages. Where conflicts between these two objectives arise, Swift (rightly, IMO) nearly always chooses the safety option1. However, In one feature, Swift fails on both criteria.

    I’m looking at you Selector.

    Selector is frequently used in wiring up UIButton2 and UIGestureRecognizer actions, and this is the syntax…

    button.addTarget(self, action: Selector("buttonPressed:"), forControlEvents: .TouchUpInside)
    

    A big red flag is that Selector is created with a String argument. As of Xcode 7, this string does not autocomplete (making it slow and error prone to type) and is not checked by the compiler to see if a method on the target matches the signature described by the Selector. The latter means that the following code will happily compile…

    button.addTarget(self, action: Selector("whyDoesThisEvenCompile:"), forControlEvents: .TouchUpInside)
    

    Tapping the button results in…

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SomeApp.ViewController whyDoesThisEvenCompile:]: unrecognized selector sent to instance 0x145e07fa0' 
    

    It is neither convenient nor safe. It just kinda sucks. On top of this, you don’t even get the good stuff from Objective-C. You can’t even invoke Selectors in Swift. They’re a glossed over backward-compatibility feature.

    To be safe, Selectors need more type information. I suggest something like…

    //NOT REAL SWIFT CODE
    let selector = Selector(ViewController.Type, @buttonPressed:)
    viewController.performSelector(selector, someObject)
    

    @ is a thing I made up, but it kinda fits the idea of “messaging” an instance. I’m no expert in compilers, but it seems this could be statically checked3. ViewController has a method called buttonPressed that takes an AnyObject parameter, and someObject is an instance of AnyObject. This example alone would eliminate a whole class of errors. A nice extension of this concept is a Target consisting of an object and a Selector, which would replace the target-action idiom.

    //NOT REAL SWIFT CODE
    button.addTarget(Target(self, @buttonPressed:), forControlEvents: .TouchUpInside)
    

    Going further, now that perform selector is back (and in slight contradiction to my earlier sentiment), I would maintain a way to create a selector from a String. Optional Selectors could provide a way to safely introduce some powerful options for things like json deserialization…

    //NOT REAL SWIFT CODE
    //Take all keys from dictionary and set the value on the matching selector in the model.
    for let key in dictionary.allKeys {
    	let value = dictionary[key]
    	if let selector = Selector(ModelObject.Type, jsonKey, value.Type) {
    		// Our class has a setter for jsonKey that takes the specified value
    		modelObject.performSelector(selector, value)
    	}
    }
    

    I’m sure this breaks down in a fundamental way I’m not fully considering, but I’d like to see more introspection and reflection options provided in Swift (assuming they’re both safe and syntactically concise :).

    1. Overtime, syntactic sugar can be added to make cleaner code, but safety (and a reputation for safety) is a hard thing to gain back once lost.

    2. Maybe I should just use Reactive Cocoa.

    3. Objective-C already throws a warning when a selector can’t be found, Swift should be capable of turning this into an error.

  • Swift 2.0 1.2 reduces nesting

    [UPDATE] This is actually a Swift 1.2 feature. My bad. It’s still nice.

    Just last week, I made light of the amount of nesting sometimes required when doing optional checking in Swift code. The code in that image reads json and then creates a model object. Something like…

    //Swift 1.0
    if let identifier = dictionary["identifier"] as? String {
    	if let name = dictionary["name"] as? String {
    		if let description = dictionary["description"] as? String {
    			let item = Item(identifier, name: name, description: description)
    			//do something...
    		}
    	}
    }
    

    While the type checks and guaranteed values provide safety, this is an incredibly common pattern and a bit ungainly as the nesting gets deeper. Fortunately, Swift 2 1.2 adds a way to do these same checks in a much more concise manner.

    A new feature of if statements allows multiple, comma separated, let declarations in the condition. The code sample above becomes…

    //Swift 1.2
    if let identifier = dictionary["identifier"] as? String,
       let name = dictionary["name"] as? String,
       let description = dictionary["description"] as? String {
    	 let item = Item(identifier, name: name, description: description)
    	 //do something...
    }
    

    Even in this simple example, two levels of nesting are removed by this small change while maintaining all safety checks. As an added bonus, this also can be used with the new guard keyword. It may be syntactic sugar, but at least it’s sweet.