My Airbnb Experience

October 14th, 2013

I was just in Montreal for a few days for Çingleton. More about that later. This post is about Airbnb.

By the time I received my invitation for Çingleton, the lovely Hotel Nelligan was booked up.  Looking for a place to stay, I decided to try out Airbnb.  

I love the Airbnb concept.  In a nutshell, it’s a way to connect travellers with individuals who have accommodations they’d like to rent out.  Anyone can list their home, apartment, or any other space, and folks looking for a place to stay can browse, reserve and pay for their reservation all through the site.

It was all very straightforward, and the host whose loft apartment I stayed in was wonderful.  But there were a few unanticipated aspects of the Airbnb experience that I wanted to mention.

On the one hand, it’s great that the place is yours and yours alone, for the duration of your stay. But this does mean you’re on your own.  Nobody comes in and moves your stuff, but nobody comes in and tidies the place up every day either.  

Staying in a city whose native language you don't speak, in a residential setting, you’re much more likely to encounter people who don’t speak your language than at a hotel.  This wouldn’t normally be a problem, but in cases where you’re renting a unit in a building where other people live (which seems common), you’re likely to run across people waiting for the elevator or in the parking garage, and they may be curious about who you are.

Some residents in condo buildings aren’t happy about having units in the building rented out.  I can understand this.  But it made me a little uncomfortable thinking that I may not be welcome by the people I’d meet in the building. 

Another aspect of Airbnb is the non-professional nature of the thing.  I expect that checking the reviews of the host before making a reservation would go a long way towards ensuring you don’t have any trouble, but just before leaving, I read about the number of Airbnb hosts who have cancelled reservations at the last minute, and boy, would that have been inconvenient.  Didn’t happen to me, but I did end up worrying about it.

I think that’s the most significant difference in booking Airbnb vs booking a traditional hotel.  With a hotel, you know what to expect, which contributes to peace of mind.

In the end it turned out wonderfully, and while these were things that were on my mind, I will use Airbnb again.  

M7 Data

September 28th, 2013

I installed the Argus activity tracking app yesterday, and was surprised to discover that it was showing me my footstep data from the day I purchased my iPhone 5S.

The iPhone 5S has the M7 motion co-processor, which can track activity in the background.  The way I expected this to work is that an application would ask for data and then go to sleep, and the M7 would track the data and hand it to the app when the app woke up.

What actually happens is that the activity is logged all the time, whether any app is asking for it or not.  Essentially there's a system store of activity data that apps can query.

This is a huge difference.  For one thing, it means that, like my experience with Argus, any app can come along and present my activity data.  You don't have to pick one app to track your steps; you can use any app to view the step data. This is excellent.

And I think this creates some clear next steps for Apple.  A logical addition to this system would be external hardware bits that can track activity separately from what the phone itself can measure.

This could be as simple as an iPod Shuffle with an M7 in it, that would sync that data to your iPhone.  Go for a run with your iPod strapped to your arm and then let it sync the data to the activity store on the iPhone.  Many people already run with an iPod of some sort, and this would mean one less device to strap on.

This can also extend to other activity tracking metrics, like heart rate, blood pressure, weight, calories consumed or whatever else.  The fitness tracking arena is incredibly fragmented right now, with dozens of services attempting to sync with each other.  It's a real hassle, but also an area that's growing like mad.

The iPhone would become your activity tracking hub

Downloadable Fonts in iOS 7

September 28th, 2013

iOS 7 has significantly expanded the number of downloadable fonts available for iOS apps.

iOS 6 supported downloadable fonts. This is hinted at in Apple’s Tech Note HT5484, which says “Apps can also install the following fonts as necessary”.

The fonts available to install mostly provided support for non-English text.

With iOS 7, they’ve expanded the list of fonts to include, as of this writing, 283 fonts. The font list is dynamic, so this may change.

Some of the highlights are: Bookman Old Style, Century Gothic, Garamond, Iowan Old Style, New Peninim (can't find a good link for this one), PT Sans, and some ornamental fonts like Wingdings. And Comic Sans. Full list here.

You can explore the downloadable font list on your iPhone using my Unicode Character Viewer app in the App Store.  

Discovering Available Fonts

Discovering the fonts available for download is done through a function that’s been with us for a while, CTFontDescriptorCreateMatchingFontDescriptors.

What’s new in iOS 7 is that you can ask this function for fonts that have the kCTFontDownloadableAttribute set, and that the function may make a network call to get the font list.  This will take an indeterminate amount of time, and is synchronous, so don’t call it on your main thread.

This function will return an array of UIFontDescriptor objects, which you can enumerate to discover the fonts available for download.

Here's a code snippet that will retrieve the font list in a useful form: https://gist.github.com/fdstevex/6741638.

Downloading Fonts

Once you know what font you want, the next step is downloading it. Before downloading it, ensure that it’s not already available by simply trying to open it. If you can open it, then it’s already on the device. If not, you’ll need to download it.

The function you use to download fonts is CTFontDescriptorMatchFontDescriptorsWithProgressHandler. This function is not included in the iOS 7 documentation yet, but is mentioned in the API diffs, and is demonstrated in the DownloadFont sample that Apple provides, so this function is safe to use in App Store apps.

The progress handler you pass to this function is called at various times during the download to let you know how the download is going.  You can use this to update a progress indicator to keep the user informed of the download progress.

I've created a simple Cocoa wrapper for this function that uses a delegate to notify the application of download progress.  It's on github: FDSFontDownloader

Using in Your Apps

Having these fonts available is great, but how do we let users use them in our applications?

My application Resume Designer supports downloadable fonts on iOS 7.  (And it's a great app, so you should buy it, or gift a copy to a friend who needs a job).  I'll describe how I implemented it.

First off, the font list you get back from this API is too long to simply present to the user.  There are a lot of fonts that are specific to certain locales (and you can filter for those - Unicode Character Viewer shows the locale to the right of the downloadable font names).  What I did is go through all the available fonts, and whittle the list down to fonts that I thought might be good choices for using in a résumé.  

That 283 number includes variations like bold and italic, and generally you don't want to present these to the user separately.  The user chooses the font family, and then sets attributes like bold and italic on portions of text to choose the variants. In the end I chose small set of 13 font families to make available as downloadable fonts.

When presenting the font list, you won't have the ability to render a preview using the font itself.  A good experience here would be to include a bitmap font sample with the app so you can present it in the UI, but you should indicate that the font will require a download.

When the user selects a downloadable font that hasn't already been downloaded, you obviously need to download it.  Because this is essentially a synchronous operation from the user's perspective (although not in code), show a progress indicator while the user waits for the font download.  The fonts are small enough that this takes just a few seconds.

An important thing to remember with downloadable fonts is that they may not be on the device the next time the user opens your app.  If the user chooses a download font, exits your app, and then does a wipe/restore on their device, or buys a new device, or opens the file on a different device (if you support iCloud or some other sync mechanism), then the app will find the font is missing. You must support a fallback mechanism.

When the user opens a document that requires a font that isn't present, download the font.  The user will have to wait a few seconds to open the document, but then it will appear as they left it.

The user may be offline when opening the document, and that's when you'd use the fallback font.

The strategy I've chosen in Resume Designer is to simply use a predefined font as a fallback, inform the user that the app is using a fallback font, but leave the download font name in the document.  That way, the user can edit the document while offline (with the fallback font) but later they can open the document with a network connection and go back to using the chosen font.  Or the user can select a font that is present on the device.

Development and Troubleshooting

When you call CTFontDescriptorCreateMatchingFontDescriptors, the system will make a request for this URL:

http://mesu.apple.com/assets/com_apple_MobileAsset_Font/com_apple_MobileAsset_Font.xml

Hit that URL and you'll get an XML list of all the fonts available to download, including a lot of extra information.  Better to get the information through the API, since this format isn't documented and may change, but it's a good way to examine the font list.

In testing, you'll want to re-download a font you've already downloaded.  This is easy enough on the simulator, as the fonts are stored in your Application Support directory:

~/Application Support/iPhone Simulator/7.0/Library/Assets/com_apple_MobileAsset_Font

Delete them, restart the simulator, and you can download them again.

On an actual device, I'm not aware of any way to remove the downloaded fonts.  Letting users download fonts is going to consume space on the device, and I'm not sure if the OS ever reclaims that space.  Something to think about.

The FDSFontDownloader code on GitHub is a good place to get started.

Core Data is pretty fast

September 13th, 2013

There's an article in the excellent online magazine objc.io by Brent Simmons on the topic of using SQLite instead of Core Data.  An example I've heard cited before is Brent's example that he uses in this article of "what if you need to mark 10,000 items as read?".

This is a compelling example because with SQL, you can update all the records with a single statement, whereas with Core Data you need to actually walk all 10,000 items and retrieve and update them.  But how long does it actually take?

I put together a simple test app that creates 10,000 entities and saves them.  Code here.

On my iPhone 5, the output from this little snippet of code is:

2013-09-13 20:09:35.979 CoreDataPerf[5874:60b] Creating Entities

2013-09-13 20:09:36.932 CoreDataPerf[5874:60b] Created and saved 10,000 entities

2013-09-13 20:09:37.822 CoreDataPerf[5874:60b] Updated 10,000 entities

 

890 milliseconds. 
 
Not great, not terrible.  Better than I expected, actually, but I could see this being a problem in an app that frequently needed to operate across all the items. 
 

Is Touch ID Innovation?

September 12th, 2013

Some folks are complaining that there wasn't enough "innovation" in Apple's iPhone 5s and 5c announcements.  But I think the 5s represents the kind of innovation Apple does best.  I'm talking about the fingerprint scanning.

A few years ago, backups were a pain in the butt.  Apple did something amazing with Time Machine in that they made backup not just a system feature, but something that people really use.  It's not hard to find people who recovered from data loss or hardware disaster thanks to their Time Machine backups.

Everyone knew they needed backups, and knew the risk of not having current backups, but Time Machine is what kicked a lot of people into having a reasonable backup strategy.  Time Machine did this through not just building a reasonably well engineered backup solution, but by nailing the user experience.

Today, passwords are a similar problem.  Everyone knows they should use a different password on every site.  Everyone knows they should have a strong lock code on their phone.  But most people don't.  Nobody likes remembering and typing long complex passwords, so most people don't. 

Touch ID and iCloud Keychain have the potential to change this.  iCloud Keychain lets you have a strong password on every site without having to remember the password - the way 1Password does - and with Touch ID, your fingerprint serves as the strong master password you need to unlock the keychain.

Apple has made it so that millions of users will follow good security practices, just as they helped users not lose data. 

Is that innovation?  I think so.

Disney Infinity

August 20th, 2013

Disney Infinity is a fascinating game. 

I had high hopes before it's release. Disney has a lot of great characters, and Disney Interactive has done some really interesting, innovative things over the years. ToonTown Online brought the MMO genre to kids over 10 years ago and is still going strong. 

Disney Infinity is, in many ways, better than I expected. The the first 5 minutes or so of gameplay has a cinematic flair that's definitely Disney. There's a strong creative team behind this, and it's evidenced throughout. 

In case you're not familiar with it already: Disney Infinity is a game that comes with a USB base that has three RFID pads upon which you place toys. One of the pads selects which world you're playing in, and the other two pads are for the characters your'e going to use in the world. Want to play in the Cars world with Mater and Lightning? Drop the appropriate items on the pad.

There are "play sets", which are levels that are hand-crafted for a specific open-world game experience. The Cars play set is kind of a Warcraft meets GTA style, where you can just drive around smashing things up if you like, or you can do quests using the familiar exclamation mark to identify a quest-giver and question mark to identify a quest endpoint.

And then there's the "Toy Box", where you can take the items you've unlocked and use them to build things, LittleBigPlanet style. You can start with a blank slate and build up some very fun environments.

Fun is a key word here. It sounds suspicious to say that the game is designed to feel like playing with toys, but that's what they set out to build (according to John Lasseter, who's got some cred in my book) and they really nailed this. It's a ton of fun simply playing in Toy Box with my son (who is 7), creating simple scenarios, playing with them, and then destroying them in crazy ways.

One stroke of brilliance is that the game rarely forces you to work directly with the other person you're playing with. If one of you wants to go into build mode and work on a part of the world, the other person can just keep doing whatever they want to do. There are areas where this isn't true, but often enough the fun is in playing in the same world with your partner instead of directly with them.

This makes it more like playing with physical toys, where you can come together when you want, play separately when you want, and there's no mode switch in the middle. You just play.

The Disney Infinity toys are RFID based.  Activision's Skylanders uses RFID toys as well, but Skylanders has been around for a while and has a number of generations of toys available. The newer Skylanders, the Giants and Lightcore models, have lights in them that are powered by the Skylanders base. Interestingly, the Lightcore Skylanders light up when you place them on the Infinity base (although of course the game doesn't recognise them). So I expect we'll see illuminated Disney Infinity characters in the future.

One of the most amazing things in my mind about Disney Infinity is the leap of faith it must have taken at Disney to allow their IP to be mashed up this way. You can take Disney trademarks like Cinderella's Castle or the Epcot ball, drop them into your Toy Box world, and then do all kinds of crazy things in and around them. Give Jack Sparrow a jetpack and fly to the top of the castle. Switch to Mater and then drive right off. Fun stuff. But can't you just imagine someone at Disney saying "No! No! No!"?

If you're a patient sort I think it may be worth waiting until the next generation consoles before picking up Disney Infinity. The Toy Box has a limit to the number of items you can place in it, and this is determined by how much horsepower your console has. And the load times are painful, at least on the Wii U where I'm playing it. But they have promised that the toys will be forward-compatible, so getting started today won't mean buying all new toys for Disney Infinity 2.

Android vs iOS Development Estimates

July 30th, 2013

I've built Android software and I've built iOS software.  I much prefer developing on iOS so that's what I spend most of my time doing, but I've done enough Android to have my two cents to contribute on this issue.

In a nutshell:  BBC said that they have almost 3x the number of developers working on their Android app as their iOS app.  Justin Williams says that this doesn't necessarily mean that it's 3x harder to build an Android app.

And of course Justin is right, but my take is that the truth is somewhere in between.

iOS is somewhat fragmented itself these days.  It's a lot of work building an app that can span iOS 6 and iOS 7, iPad, iPhone 3.5" and iPhone 4".  But my actual experience building apps that support all these devices is that it's much easier to deal with the minimal fragmentation in iOS than it is the massive fragmentation in Android.

The problem with Android is you need to support some seriously old devices and operating systems, or else you drop a third of all the Android devices off your supported devices list.  Most apps need to support not just a huge range of screen sizes but varying amounts of memory, GPU, and button availability.

Building an Android app that supports Android 4.0+ across a single tablet and a single phone would be roughly equivalent to building an iOS app of similar complexity, assuming the app didn't depend on some Cocoa framework that just isn't available on Android.  (For example, good luck generating a PDF from an Android app).

But then add support for Android 2.3.  Add support for low memory devices.  Add time for testing on a wider range of devices.  Extra time for tuning to try to get smooth performance on slower devices.

And add time for the emulator that Android developers have to use.  A typical edit/compile/test cycle simply takes longer with the Android tools than it does with Xcode.  It all adds up.

If I had to come up with a guideline, I'd say building an Android app would take 1.5x to 2x as long as an equivalent iOS app.

Upgrade Pricing and Used Apps

July 16th, 2013

The Mac and iOS App Stores don't offer upgrade pricing, and they probably never will.

Apple's model for apps is akin to physical products.  If you bought a toaster last year, and this year a new toaster comes out, there is no upgrade path.  Your old toaster still works.  If you want the new one, you buy it.

This puts the onus on software developers to charge a low enough price for the software that buying it again seems reasonable.  It also means developers need to add features compelling enough to get users to pay for the software again. 

As software developers, we feel like we have to update existing applications when circumstances change.  And customers have been trained to expect it.  If Twitter changes and breaks TweetBot, we just expect a free update to TweetBot to support those changes.  

Apple's model offers two solutions.  Provide a free update, or ask users to pay for a new version.

If a user is using an old version of an app that doesn't work anymore (because it's not compatible with their new device, for example, or because the web service API it depends on has changed), they will have to buy the new one if they want to continue using it.  People don't need to be trained to expect things to work this way; that's how the world works.  

We need to stop training users to expect free or inexpensive upgrades, and move to less frequent, "big bang" updates that add a lot of value at once and are worthy of repurchasing the app.

If developers can keep prices reasonable then this isn't such an unworkable solution.  Spending $9.99 once a year for an app that you use frequently is still pretty reasonable.  Or even spending $199 for an app that's an integral part of your business.

An important difference between the App Store and the real world is that if I buy the 2013 toaster, I can sell my 2012 toaster.  It still has value.  

Because you can't sell apps, their residual value is zero.  If you spent $199 for Logic 10 in 2012 and you spend another $199 for Logic Pro X in 2013, that $199 you spent last year is gone.  You will get none of that value back.

That's really the missing piece to treating apps as physical goods. 

With the Xbox One, Microsoft initially proposed a way to compensate developers for sales of used goods, and maybe there's a solution in there somewhere.

Imagine a "Used App Store" where you could list your apps for sale.  Post your previous version of an app for $50.  Apple takes a commission, the developer gets a percentage, and you get the remainder.  Everyone wins.

I'm not holding my breath.

Measuring glyphs on iOS

May 26th, 2013

Between Resume Designer and Unicode Character Viewer, I've done a fair bit of laying out text by hand on iOS.

Part of laying out text is measuring it. And iOS sucks at that.

Here are two examples.

In Resume Designer, I'm using CTFramesetterSuggestFrameSizeWithConstraints to measure paragraphs and then drawing into that frame.  I noticed that occasionally (but not always), the last line of text would go missing.  It just wouldn't fit into the "suggested" frame.

If you search for CTFramesetterSuggestFrameSizeWithConstraints, the first four results you find are people having the same problem.

The solution is simply to pad the height a bit.  That's what I ended up doing, and that cleared up my problem.

NewImage

The second example is in Unicode Character Viewer.  The purpose of this app is to make it easy to find beautiful glyphs in the fonts that come with iOS.  I'm sure the market for this sort of thing is very small (maybe just me) but I wanted a way to simply browse glyphs.

Part of this is drawing the glyph, and part of drawing it is I need the extent.  Simple enough, right?  [NSString sizeWithFont:] should tell me how big the glyph is.  Except it doesn't.

That's a screenshot of the app showing a particular glyph, that doesn't fit into the rectangle that [NSString sizeWithFont:] returns. There are lots of these edge cases, particularly in swoopy fonts like SnellRoundhand and Zapfino.

Figuring there must be a way, I used one of my two-per-year Apple support cases to ask Apple what the right way to do this is.  The first answer I got seemed promising.

The suggestion was to drop to using Core Text to measure instead of UIKit, and use CTLineGetBoundsWithOptions, passing kCTLineBoundsUseGlyphPathBounds as an option.  This is new to iOS 6, which seemed promising.

And that did fix the problem for the sample glyph with SnellRoundhand, but when I tried the same glyph with Zapfino, it still extended beyond the measured bounds.

I bounced this off Apple and the response I got?

"We don't have an API that is perfectly reliable for getting the glyph bounds for all the fonts"

So for all the great text support in iOS (and it really is great), the one thing it can't do is reliably tell you how big the text is going to be.

In my Unicode app I contemplated measuring the glyphs myself by drawing them into a much bigger rectangle and then cropping to non-whitespace, but in the end I think just adding enough arbitrary padding will suit my purposes.  

Anyway, hopefully if you run across this post because your glyph measuring seems broken, I can save you a few hours of research and just give you a Jim Dalrymple style answer, "Yep".

 

Be Careful What You Wish For

May 20th, 2013

Last week Google IO, Google introduced their new app analytics for the Google Play platform.  This will make it possible for app developers to learn how users are discovering their apps.  Developers who spend money on ad buys will be able to correlate ad spend with sales, 

Apple's developers, meanwhile, have no support at all from Apple for things like this.  You can determine how many copies you sold, and in what country, but that's about it.   There are some hacks that developers can use to try to find some of this data, like tracking redirects from ad pages, but it's not a very reliable system.

Twitter sentiment during the introduction, even among popular iOS developers was decrying iTunes Connect and praising Google.  A lot of people are hoping that Apple will introduce something similar at WWDC next month.

But I'm not one of them.

Here's the problem.  If Apple gives us this data, then we'll have to use it to compete.  

I have no doubt that, given two roughly equivalent apps, the one that does a better job of promoting the app will sell better.  Better SEO, more targeted advertising, better PR, etc.

At this point you're probably thinking "well, yeah, that sounds right".  But this means that now both of these developers are going to need to spend time on SEO, ad buying and targeting, and PR. 

This was all stuff that you can mostly ignore today, because it really doesn't pay off.  There are no broadcast channels where you can advertise a $2.99 app that are cost-effective.  

PR works, but PR is responsible for the App Store phenomenon where you get a big burst of initial sales and then your sales drop off to noise level as the buzz dies.  Nobody can keep the buzz going forever, and if the only way users are going to find your app is through the media, then that drop off is going to happen.

On the other hand, think about the great apps that you use.  How did you discover them?

I'll bet it was through Twitter, through search within the App Store, or through the App Store curation (Editor's Pick's, that sort of thing).  It may have been through the media - that does definitely work - but beyond the initial buzz, that's not how you create sustaining sales.

Will users spend more money on Google Play now that app developers have these tools?  I don't think so.  I think users will spend the same amount on apps, but this may influence them to spend their money on different apps.  Will the apps they find be better?  Or simply the ones that put the most time and effort into SEO or advertising?

I prefer a world where spending time making your app better will pay off more than spending time and money on advertising, because if advertising works, we'll have to do it.

Today, in the App Store, the incentive is on building the best apps. Not the best app marketing machine. And I hope Apple doesn't break that.