Monday, October 15, 2012

Bundling Python files into a stand-alone executable


One of the problems with building a medium to large sized program in Python (or similar scripting languages) is distributing it to users. When a Python script grows beyond a couple hundred lines, most programmers prefer to split that single script file into multiple Python modules and packages. For an individual developer, modules and packages are primarily an aid in mental organization, though they also ease navigating around the project. For a large Python program being developed by a team, modules and packages are an important way to communicate the structure and intent of the code.

Unfortunately, distributing a multi-module Python program has a number of problems. First, you must carefully assemble all your program's dependencies in a single directory tree. Second, you need to make a zip or tarball of the directory tree for distribution. Third, you need to instruct your end users on how to unpack the zipped or tarballed program and how to correctly set their PYTHONPATH and which Python file or shell script in the directory tree to invoke to run your program.

Python has long included the distutils module to help developers distribute Python code. Distutils is focused on distributing Python modules and packages for use by other Python developers and is great for its intended purpose; it can also install shell scripts in the standard operating system command directory (such as /usr/local/bin on most UNIX-derived systems). It has a big problem though: Python libraries installed by distutils are made available to all Python code unless special care is taken. If you include any common third-party libraries in your program, you run the risk that your end user may have a different, possibly incompatible version of that library already on their system. You risk breaking other Python programs, and being broken in turn if you share libraries. Windows users have long dealt with DLL Hell, a similar problem where different Windows applications would install incompatible versions of shared libraries.

Today even the computer in your pocket has dozens of gigabytes of storage so modern development has moved away from sharing library code between programs. For Python developers, virtualenv allows you to quickly and easily create separate virtual Python installations on a single computer, each one isolated from the others and from the "real" Python installation. You can install Python modules and packages in one virtualenv without affecting the others. Used along with the pip package manager, it's easy to document and recreate a virtualenv Python environment, which is a boon to Python web developers.

Virtualenv is still overkill for end users, technical or not, who simply want to run your program in order to get their work done. Fortunately, Python quietly added a new feature in 2.5 that makes it possible to bundle up a directory full of Python code into a single executable file. I say "quietly" because Python 2.5 was released in 2006 and I only heard about this feature now in 2012, six years later. (Okay, it's possible I wasn't paying close attention. :-) Typical of Python, the feature isn't pretty but it has a certain elegance to it: the __main__.py file.

How to use a __main__.py file
The Python documentation for the __main__.py file explains its purpose succinctly but barely hints at the possibilities. I'll try to do a better job. Lets start by creating a directory for our Python application named app:
$ mkdir app
Now open your favorite text editor and create the file app/__main__.py. Add the following code to it:
# file app/__main__.py

def main():
  print('The rain in Spain falls mainly in the plain.')

if __name__ == '__main__':
  main()
If you've done some Python programming, you'll recognize the __name__ == '__main__' idiom used to determine if a python module is being executed directly rather than imported as a module. When it's executed directly, the example simply calls the main() function, which prints "The rain in Spain falls mainly in the plain." to standard out.

Now let's run this program. Instead of calling __main__.py directly, we can treat the app directory as our Python program:
$ python app
The Python interpreter sees that app is a directory and checks for a __main__.py file inside it. Note that Python only checks the top level of the directory; it doesn't search subdirectories. Since there is a __main__.py directly in app, the interpreter runs it and the output is:
The rain in Spain falls mainly in the plain.

In addition, the Python interpreter will add the directory to the start of sys.path so that all imports will check the that directory first. By placing all of the modules and packages that our program depends on in the directory, we can stay isolated from whatever versions the end user may have installed as well as keep our dependencies isolated from the end user's system.

Zip it up
Python has supported loading modules and packages out of a zip file since 2.3. Just as it now looks in a directory for __main__.py, Python will also look in a zip file for __main__.py. Let's zip up the app directory and test this.

Note that the __main__.py file needs to be at the top level in the zip container, not in a subdirectory. This makes creating the zip file a little tricky. We want to recursively zip up everything in our app directory, but not include the app directory itself. (Windows users will need a command line zip program to follow along.)
$ cd app
$ zip -r ../app.zip *
$ cd ..
(Use *.* instead of * on Windows.)

To test that you've zipped things up correctly, run your Python program directly from the zip file:
$ python app.zip
You should see the expected output:
The rain in Spain falls mainly in the plain.

Python will place the zip file first on sys.path just as it does for a directory; all modules and packages imports will search the zip file first. Be sure to place your modules and packages at the top level in your directory along side the __main__.py file.

Load a resource
If you've put all your Python code in the right place using this scheme, everything pretty much just works as you expect it to. But some programs depends on resources aside from Python code, and need to load various data files that come bundled with the program. The easiest way to find and load a program bundle like this is to use the pkg_resources module. The pkg_resources module does a lot of things, but you'll want to look first at the ResourceManager API which has the most common functions for finding and loading resource files.

Let's add a resource file to our little app and load it using the pkg_resources.resource_string function. Create a subdirectory under app called resources.
$ mkdir app/resources
Using your favorite text editor again, create the file app/resources/inFrance.txt and add some text to it:
But the ants in France are mainly in your pants.
Now edit app/__main__.py so that it looks like this:
# file app/__main__.py

import pkg_resources

def main():
  print('The rain in Spain falls mainly in the plain.')
  print(pkg_resources.resource_string('resources', 'inFrance.txt'))

if __name__ == '__main__':
  main()
You may already have pkg_resources.py installed on your system. If you don't, you'll find it's part of the distribute package. Download the latest version of distribute, unpack the tarball and find pkg_resources.py inside. Copy pkg_resources.py to app/pkg_resources.py. (Even if you already have the pkg_resources module on your system, if you use it in your program, you should add it to your bundle before distributing it to others.)

Now when you run the program:
$ python app
You should see this output:
The rain in Spain falls mainly in the plain.
But the ants in France are mainly in your pants.

Make it executable
Finally, you can turn your zipped program bundle into a stand-along executable on UNIX-like systems using a couple of commands. Zip up the latest version of the program in the app directory and name it app2.zip.
$ cd app
$ zip -r ../app2.zip *
$ cd ..
Now use a bit of UNIX magic to turn app2.zip into an executable.
$ echo '#!/usr/bin/env python' | cat - app2.zip > app2
$ chmod +x app2
The first command inserts a UNIX shebang at the start of the zip file and writes it to a new file called simply app2. The zip file format is designed to allow a small executable program to be inserted at the front (that's how self-extracting zip files are created), so this is kosher and doesn't corrupt the zip file. The second command sets the executable bits on app2.

Now you can simply run app2 like any executable.
$ ./app2
And you should see the expected output.
The rain in Spain falls mainly in the plain.
But the ants in France are mainly in your pants.

Wednesday, October 10, 2012

BSD-style license for code

We have published a fair amount of source code on the Able Pear Software blog over the past few years, but we neglected to specify any kind of software license to go along with it. We occasionally get asked about an open source license (the UrlEncoding category for NSDictionary is particularly popular).

All the code we publish on the Able Pear Blog is free for you to use under a BSD-style license, as is our Autoindigestion tool. We like the simplicity of unrestrictive open source licenses like the BSD and MIT licenses. If you decide to incorporate some of our code into your project or product, we'd love to know. Modern software is so complex, it's simply not practical to write everything from scratch. Many parts of OS X and iOS have their roots in the FreeBSD project, which itself is a descendant of BSD UNIX. Even Microsoft has incorporated some BSD code in Windows.

Here is the Able Pear Software blog open source code license. Adjust the copyright year to match the date on the blog post. (Please note that the full text of the blog is not included in this license, only the source code.)
Copyright (c) 2012, Able Pear Software Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Monday, October 8, 2012

Smart App Banners

The new version of Mobile Safari that ships with iOS 6 has a great new feature for app publishers: Smart App Banners.
When a user visits your site in Mobile Safari on iOS, you can now add a pop-up banner to promote your iOS app, which includes a direct link to the app in the App Store and optionally your iTunes affiliate information. David Smith has a great overview on his blog, and you can find all the details of Smart App Banners in Apple's Safari Web Content Guide on the Apple developer site.

Though I doubt that this will do away with all those annoying full-page "get our iPad app" pop-ups, I hope that at least some sites will start to use this instead. Thanks Apple for providing something to help sites promote their apps in a less annoying way.

Monday, July 30, 2012

Adding a Retina-ready icon to your Mac app in three easy steps

I've been doing more OS X development recently, and coming from the iOS world, there's a lot that's familiar but I still stumble over many things. Creating an app icon is one of them. After some poking around, I've discovered what you need to do to create a custom icon for your modern Mac app.

Step 1: Create the icon images
Modern Mac icons pack five different resolutions in one .icns file, from 16x16 to 512x512:
  • icon_16x16.png
  • icon_32x32.png
  • icon_128x128.png
  • icon_256x256.png
  • icon_512x512.png
The dimensions are actually "points" rather than "pixels". On standard resolution displays, 1 point == 1 pixel; iOS developers are already familiar with handling "retina" resolution displays where 1 point == 2 pixels. These double resolution "retina" resources get "@2x" added to the base filename, so in addition to the five standard resolution icon images, you now need five double resolution ones:
  • icon_16x16@2x.png
  • icon_32x32@2x.png
  • icon_128x128@2x.png
  • icon_256x256@2x.png
  • icon_512x512@2x.png
The names describe the icon size in points, so icon_16x16@2x.png is 32 by 32 pixels and icon_512x512@2x.png is 1024 by 1024 pixels. Some of these images have equivalent pixel sizes: icon_32x32.png and icon_16x16@2x.png are both 32 by 32 pixels. You may be able to get away with using the same bitmap in many cases, but you (or your icon designer) may want to tweak each version to look best on their respective display types.

Step 2: Add an .iconset to the Xcode project
In the olden days, you would use the Icon Composer app to build your .icns file, but it's no longer being updated by Apple and doesn't support double resolution images. Today, Xcode will build your .icns file automatically for you. (Alternately you can use the iconutil command line utility to build .icns with high res images or to extract images from .icns files; see Apple's High Resolution Guidelines for OS X for details.)

The trick to making Xcode build your .icns automatically is to put your set of icon images in a folder named <ICON_NAME>.iconset, where <ICON_NAME> becomes the base name for your .icns file. Add this folder to your Xcode project and Xcode will then create <ICON_NAME>.icns when you build, and automatically copy it to your app bundle.

Note that the images in the .iconset directory need to have the names given above: "icon_16x16.png" through "icon_512x512@2x.png" or you will see a warning in Xcode when building your project and the mis-named images won't be included.

Step 3: Add the icon to the Info.plist
To set your app's main icon, add the "Icon File" key to your app's Info.plist file and set the value to <ICON_NAME> (without the .icns extension). If you used the standard Xcode template to create your app, your Info.plist will be named "<APP_NAME>-Info.plist", where <APP_NAME> is your app or project name. For those of you who like to edit your .plist files as XML, the key name is CFBundleIconFile.

You can also drag the .iconset directory from the finder or the Xcode project navigator to the "App Icon" pane of the Summary tab for your app's target (pictured above). If you use this approach, Xcode will insist on copying the .iconset into the root folder of your project, even if you've already added the .iconset somewhere else in your project's directory tree (<sarcasm>another great example of Apple's attention to detail</sarcasm>.) If you're not fussy about your project organization, you can simply let Xcode have its way; otherwise you can remove the copy Xcode makes and add the .iconset in a more appropriate place, like the Resources folder; just make sure to leave the "Icon File" key in your Info.plist and Xcode will show the icon in the "App Icon" pane.

Easy as 1-2-3
Not hard once you figure it out, and a nicer workflow than having to wrestle with a half-baked special purpose app like Icon Composer.

Monday, July 9, 2012

Download iTunes Connect sales reports with Autoindigestion

When you start selling your first app in the app store, it's very exciting to check you sales every day in iTunes Connect. After the initial excitement wears off and your app sales settle into a steady state, it's easy to get involved in your next project and forget to log into iTunes Connect periodically to download your daily or weekly sales reports. Apple only makes the last 14 days of daily reports and the last 13 weeks of weekly reports available; if you're not diligent, time can fly by and you will lose important sales records.

Apple does provide a tool to automate the retrieval of iTunes Connect sales reports: the Auto-Ingest tool, a small Java command line app. While it's good that Apple provides an officially supported tool, it's a very minimal one. The Auto-Ingest tool only downloads one report at a time and doesn't have any intelligence for determining which reports have already been downloaded, nor can it handle downloading multiple report types or multiple iTunes Connect vendor accounts without some scripting help. Enter Autoindigestion.

Autoindigestion is a command line utility for Mac OS X Lion that uses the Auto-Ingest tool to automatically download daily and weekly sales reports. The first time it runs, Autoindigestion will grab all available reports; on subsequent runs it will download new reports based on the current date and the dates of previously downloaded reports. If you miss a day because your system is off or iTunes Connect reports are delayed, Autoindigestion will catch up the next time it runs. Autoindigestion can also be configured to handle multiple iTunes Connect vendors, which is great if you handle sales reporting for clients.

Autoindigestion is open source and available under a BSD style license. It's currently available as source from the Autoindigestion GitHub page. It is a native OS X command line program written in Objective-C and requires Xcode to build. Complete instructions for installing and configuring Autoindigestion are included on the GitHub page. I enjoyed creating Autoindigestion and hope you find it useful.

Wednesday, June 20, 2012

WWDC 2012 Videos

Apple has posted the videos and slides from the technical sessions of this year's Worldwide Developers Conference yesterday. The videos are available for free, but you need to be a registered Apple developer to watch them. (You can register at https://developer.apple.com/.)

As in previous years, there's a lot of good stuff here for iOS and OS X developers, as well as some sessions on other parts of the Apple ecosystem like Safari and iAds. Also featured this year are several sessions related to authoring content for the iBookstore using both EPUB 3 and Apple's proprietary iBooks Author formats. There are also a good number of sessions focused on getting the most out of Xcode and the Apple toolchain.

I've watched many of the videos from previous years and they are quite useful. If you are an experienced iOS developer, these sessions are a great way to help you get up to speed on the latest stuff. If you are new to iOS, the WWDC sessions, especially from previous years, contain some great overviews that will help you get up to speed fast. I highly recommend them.

Monday, March 5, 2012

Instance Variables in the Implementation File

Xcode
Recent versions of iOS and the Apple LLVM 2.1 compiler use an improved version of libobjc, the core library that powers Objective-C features like classes and method calls. This "modern runtime" library enables a lot of new, cool flexibility in creating Objective-C classes. One of my favorite new features is Instance Variables in the Implementation File, which allows you to move your private instance variables out of your .h files. iOS developer Tips shows you how.

Friday, February 24, 2012

Something wonderful: new Objective-C literal syntax

mountain lion cub going rawrrrrrWith the announcement of OS X 10.8 Mountain Lion, Apple made the beta version of Xcode 4.4 and the Mountain Lion SDK available to developers enrolled in the Mac Developer Program (the US$99 annual membership required to submit apps to the Mac App Store). The new OS X version has created a lot of developer buzz around Gatekeeper, the upcoming requirement that all apps in the Mac App Store run in a restrictive sandbox similar to iOS apps. This is a big problem for makers of development tools and other specialized apps that need low level access to the system; Apple has effectively banned many of them from the App Store. On the other hand, strong argument can be made that Gatekeeper and app sandboxing will be a big win for most non-technical Mac users.

The news about Mountain Lion isn't all bad for developers. Apple keeps their beta SDKs under a non-disclosure agreement, but with developer interest high for both iOS and OS X, details tend to leak out. CocoaHeads recently revealed that the Apple LLVM 4.0 compiler in the Xcode 4.4 beta includes support for an Objective-C literal syntax for NSDictionary, NSArray and NSNumber objects.

If you've done any Objective-C programming, you've seen the NSString literal syntax:
// NSString literal
NSString *name1 = @"Lana Kane";

// creating NSString from a C string literal
NSString *name2 = [NSString stringWithCString:"Sterling Archer"
encoding:NSUTF8StringEncoding];

An NSString literal is like a plain old C string literal, but prefixed with the '@' character. This has made using NSString objects easy, such as adding them to a NSArray. Using numbers, however, meant lots of tedious calls to [NSNumber numberWithXxx:...]. Like NSString literals, the new NSNumber literals are simply the plain old C number literals prefixed with '@'. This included character literals (since characters are simply small integers of type char) as well as the BOOL values YES and NO (though technically YES and NO are #define'd constants, not literals).
// new NSNumber literals
// and old style NSNumber creation
NSNumber *intNumber1 = @42;
NSNumber *intNumber2 = [NSNumber numberWithInt:42];

NSNumber *doubleNumber1 = @3.1415926;
NSNumber *doubleNumber2 = [NSNumber numberWithDouble:3.1415926];

NSNumber *charNumber1 = @'A';
NSNumber *charNumber2 = [NSNumber numberWithChar:'A'];

NSNumber *boolNumber1 = @YES;
NSNumber *boolNumber2 = [NSNumber numberWithBool:YES];

The new syntax supports the usual number suffixes like 'f' for float and 'u' for unsigned number types.
NSNumber *unsignedIntNumber1 = @256u;
NSNumber *unsignedIntNumber2 = [NSNumber numberWithUnsignedInt:256u];

NSNumber *floatNumber1 = @2.718f;
NSNumber *floatNumber2 = [NSNumber numberWithFloat:2.718f];

Having a compact NSNumber literal makes using numbers in collections much nicer. Here's a NSArray with some strings and numbers:
// an array with string and number literals
NSArray *array1 = [NSArray arrayWithObjects:@"foo", @42, @"bar", @3.14, nil];

// and the old way
NSArray *array2 = [NSArray arrayWithObjects:@"foo",
[NSNumber numberWithInt:42],
@"bar",
[NSNumber numberWithDouble:3.14],
nil];

This would be nice all by itself, but really shines when combined with the new NSArray and NSDictionary literals. Here is the array from above using the new NSArray literal syntax:
// an array literal
NSArray *array1 = @[@"foo", @42, @"bar", @3.14];

Like many popular languages today, NSArray literals use the square bracket characters '[' and ']' to delimit the array literal; the only twist here is you prefix it with '@' symbol. And thankfully, you no longer need to remember to put nil at the end!

And there's a similar notation for NSDictionary literals:
// a dictionary literal
NSDictionary *dictionary1 = @{ @1: @"red", @2: @"green", @3: @"blue" };

// old style
NSDictionary *dictionary2 = [NSDictionary dictionaryWithObjectsAndKeys:@"red", @1,
@"green", @2,
@"blue", @3,
nil];

The curly brace characters '{' and '}' delimit the dictionary literal and the colon ':' character to separate keys and values, similar to widely used languages like Python and JavaScript, but of course prefixed with '@'. I was never a fan of the backwards "ObjectsAndKeys" way of creating a NSDictionary, and I'm glad to have a much more compact alternative.

This new syntax is basically what Ole Begemann proposed in his blog in 2010 (EDIT: and Stig Brautaset proposed in his blog in 2008, and by others even earlier) and it's great to see that Apple is actively eventually listening to their developer community and finding real ways to make Objective-C a nicer language. Along with the @property syntax and ARC, this goes a long way toward reducing boilerplate code. Objective-C's dynamic object model, inspired by Smalltalk, has always made it more akin to dynamic languages like Python and Ruby than static ones like C++ and Java. ARC and compact container literals are big steps that take Objective-C further into dynamic language territory, yet the low level power of C is always available when you need it. I can't wait until this is released.

Update: Apple has committed a patch with the new syntax to the LLVM project.

Thursday, February 16, 2012

Add "Social Networking" with the Twitter & Accounts Frameworks in iOS 5

Recently, on the iOS Developer Network (iOS DevNet) on LinkedIn, I posted a discussion on integrating "social media hubs" into your iOS 5 app and provided some references.  Here is the discussion:

There are several ways to integrate your app with Social Media hubs like Facebook and Twitter. Now with the new Accounts and Twitter frameworks in iOS 5 Apple makes it even easier.

Peter Friese has a good post on his blog covering Accounts and Twitter integration.

Lasse Bunk shows another example using JSON and Storyboards in Xcode 4.2.

More information on Working with JSON and iOS 5 can be found in Marin Todorov's post on Ray Wenderlich's blog.

You can, and should, review Apple's document on on the Twitter Framework and the Accounts Framework to become familiar with the new APIs.

In addition, and if you like the feel of paper, or use the Kindle app, Amazon is now caring Apress's Beginning iOS Apps with Facebook and Twitter APIs: for iPhone, iPad and iPod touch book.

Cheers and good luck on your app's social integration.

Monday, January 9, 2012

The year ahead for Apple: the iPad dominates (and one more thing...)

iPad
With 2012 barely a week old (and possibly the last year ever), I thought it would be a good time to make some prognostications for the tech industry in the year ahead. As an iOS developer, I pay a lot of attention to Apple, so I'll concentrate on what I think is in store for the Cupertino company. Love them or hate them, they're certain to continue to make their presence felt in 2012.

iPad continues to dominate
Apple will announce the iPad 3 in March, to begin selling sometime in late May. It will be an iteration of the existing iPad design, but a little thinner, sleeker and sporting a 2048x1536 Retina display. Tech pundits will give it mixed reviews, repeatedly pointing out that there is no LTE version, but consumers will embrace the device and Apple will again have problems meeting strong demand. In addition, Apple will keep the iPad 2 around, slashing the price of the base model to US$299. With Apple's BOM costs for the iPad 2 now falling under US$200, they maintain their profit margins and whittle away at the value proposition of competing tablets, most notably the Kindle Fire.

This isn't a big deal for Amazon; the Kindle Fire is their razor handle and Amazon's digital books, music, movies and apps are the blades. Amazon will continue to improve their Kindle line, updating the Kindle Fire software and introducing a follow-on color tablet device in a larger form factor that's more suitable for viewing movies, magazines and textbooks. The Kindle doesn't need to appeal to everyone, only to Amazon's best customers, and ensure that Amazon has a path to their digital customers outside of Apple and Google. Amazon is happy to be the Schick to Apple's Gillette in the tablet market.

For the Android tablet makers, that large sucking sound you hear is Apple continuing to vacuum up all the mobile device profits in developed countries. With Apple using their billions in cash to lock up the best values in the supply chain, Android tablet makers will be hard pressed to match the iPad's juicy margins. Making it up in volume won't be possible: with Android lacking any compelling value proposition for the general consumer, Android tablets will remain the province of open source zealots, tinkerers and Apple-haters, and sales will be anemic in developed countries. The story will be a bit different in emerging economies where US$100 is too large a differential for most consumers, but razor thin profit margins will make Android tablets a money loser for all but the most nimble device makers. The story will be brighter for Android in the phone market, where Android's "openness" aligns closely with the mobile carriers' desire for total control of their customers, but here too Apple will continue to soak up the lion's share of profits on mobile phone sales.

The sad passing of Steve Jobs won't slow Apple down this year; if anything, his spirit will continue to haunt One Infinite Loop and energize the company. Though Tim Cook is no Steve Jobs, he doesn't have to be; ultimately Apple's products will speak for themselves, as they always have. And while we will all miss watching Jobs unveil Apple's latest and greatest, there will still be one more thing...the new Apple TV.

Apple TV
Television, the Apple way
With all the rumor and speculation swirling around the forthcoming Apple TV device, from Jobs' cryptic comment in his biography that "I finally cracked it" to talk of a 50-inch Apple branded television, it's hard to see where this one might go. I'd be surprised if they announce this early in the year; Apple needs to line up enough content owners behind the new device for it to be compelling to consumers and seem inevitable to the rest of the industry. The movie studios are scared of change and will draw out negotiations. I would look for a big announcement in the late summer or early fall.

A lot of speculation focuses on what kind of UI the device might have, with talk of Siri-style voice control, but I don't think that's the most interesting thing here: I'm sure the UI will be butter smooth and easy to use, whatever form it takes. When Jobs said "I finally cracked it", I believe he was thinking at a higher level. Apple has had the technology to build a nice TV set for a long time, but they haven't because there's no money to be made there, and simply building some pretty on-screen menus isn't interesting enough. Changing the way people perceive television and building a new business model behind that is what's interesting to Apple.

How many of you remember the first Motorola ROKR? That was the first "Apple phone", a Motorola mobile phone with a built-in iPod, released in September 2005 to widespread yawns and poor sales. It's no coincidence that Apple and Motorola parted ways not long after, with Apple announcing the iPhone in January 2007. The ROKR was a learning experiment on Apple's part, a way for them to get an understanding of mobile phone technology and the business model behind it. The genius of the iPhone was in seeing what a mobile phone could be. In 2006, a mobile phone was a commoditized product that let you make phone calls, painfully type out text messages on a cramped telephone keypad and take tiny, fuzzy pictures. Most consumers just took the cheapest device they could get from their mobile carrier. In 2007, a mobile phone became your portable connection to the internet, people lined up at the Apple store to buy it and happily switched carriers to make it work. Apple makes handsome margins on the device and a little pocket change on media sales through iTunes, the carrier attracts deep pocket customers who gladly pony up US$80 a month or more for an expensive data plan, and consumers get a clean, easy to use device that gives them Internet access on the go. Making phone calls becomes almost an afterthought. While the iPhone may not be in the carrier's best interests long term, the prospect of all those free-spending Apple customers in the short term was enough to sign up one carrier in every big market.

In 2011, teevee consists is a giant flat panel with a rat's nest of wires to a craptastic cable box, DVD player and game console, along with four inscrutable 57-button remotes lying on the coffee table. People pay US$100 or more per month to their monopoly cable company for access to hundreds of streams of random programming interspersed with twenty minutes of 100 decibel commercials per hour. Consumers pay attention to exactly 3.5 hours of programming a week; the rest of the time they flick channels endlessly, searching for something good. The flat panel screen is a commodity, as are the cable box and DVD or Blu-ray player; the game console is a barely differentiated loss-leader. Apple has been playing around the periphery of this miserable, steaming technology stack for several years with their "hobby", the little Apple TV box, that lets you watch movies and TV bought on iTunes and stream Netflix. They're learning about building UIs for giant flat panels and figuring out how to negotiate with the studios to get compelling content.

Apple has a lot of interesting pieces in place. iOS devices are already eating away at the hand-held game market. Sales and rentals of videos though iTunes have value to both the content owners and consumers with disposable income: the studios get flexible pricing and detailed sales metrics, consumers get their favorite programs without the commercial, movie previews or FBI warnings and the can watch at home or on their mobile device. Content distributors like MLB and Netflix can create custom apps for both iOS and Apple TV that give them greater control over how their content is distributed. In many ways, apps are the channels of the future. Facetime video chat is a great app, especially on iPad. The Airplay feature of iOS devices is a hidden gem here, effectively turning that big flat panel into a flexible video terminal for your iPhone, iPad or iPod touch, allowing you to project your favorite movie, TV show, game or app onto the big screen for all to enjoy. Apple TV sales figures may be modest when compared to other iOS devices, but the couple of million little Apple TV boxes sold in 2011 could be just the tip of the iceberg. The killer app for Apple TV is the ability to effortlessly bore friends and neighbors with all those bad vacation photos you took.

Apple could take the Apple TV platform in a number of directions. While I would love for them to do something that would allow me to ditch my collection of 57-button remotes, more likely Apple views the DVD/Blu-ray player, cable box and game console as legacy -- they will all go away on their own soon enough. Imagine Steve Jobs watching television, cross-legged on the polished hardwood floor of a nearly empty room with just a Tiffany lamp and a sleek, 50-inch Apple branded flat screen, the slim, silver seven-button Apple remote in his hand. You wouldn't need or want anything else. If Apple does produce their own television set, simplicity will be it's main value proposition to consumers. It will be designed to stand alone rather than integrate with all those legacy devices. You won't need to hire Geek Squad to set it up, but it won't appeal to people who are heavily invested in all those legacy devices. The tech press will complain about it being closed and limited, but it will strike a chord with certain buyers, particularly the 9% of US consumers that have dropped their cable television service. I'm sure Apple has a mature prototype television set sitting in Sir Jony Ive's office in Cupertino; whether Apple thinks the world is ready for it is the real question.

For the rest of us, Apple will continue to make the inexpensive little Apple TV box. They may update the hardware this year to add Siri-style voice control, but I'm expecting the real innovation will be on how content is bought and delivered. The rumor that Apple plans to bid for rights to broadcast English Premier League soccer is intriguing. The Apple TV already comes with apps for NBA, NHL and MLB as well as the Wall Street Journal. What would your television viewing experience be like if all your cable channels became apps on Apple TV, with in-app purchase or subscriptions for premium content? How would you divvy up that US$100 a month you currently spend on cable TV among all those apps? If enough of your favorite shows were available on Apple TV, canceling your cable TV subscription would be a no-brainer. I'll bet that many of the content owners would be happy to cut out the cable companies and have better control over their relationship with viewers.

Whatever Apple does around teevee this year, you can bet that critics will deride it as too limited, closed or incompatible, just as critics derided the first iPhone and iPad. Meanwhile, Apple will be laser-focused on making their customers happy and earning generous profits in the process.

Thursday, January 5, 2012

Avoid agile dogma: recommendations not rules

Bozo the Clown
Years ago as a developer working mostly solo, I got interested in automated testing and unit testing, which in turn lead me to extreme programming (XP) and agile software methodologies. I've had the wonderful good fortune of working for Pivotal Labs a number of times in recent years and been a part of a number of successful agile projects. I know that an agile approach to project management can work well in many situations and I think I have a good understanding of how and why. But I'm not an agile zealot -- agile isn't appropriate for every type of project or organization and a good team can usually succeed using any process. Still, I think working on an XP project is more fun and rewarding for everyone involved.

I've talked with many developers who range from agile skeptic to agile detractor. They often react negatively to a particular XP or agile practice, with pair programming and unit testing being the two most common ones. Some developers are drawn to programming because they get great satisfaction from grappling with interesting intellectual challenges in solitude; agile doesn't have much to offer an individual developer when this is their top priority. If you're this kind of developer and you've found a place that gives you the freedom to work solo on cool stuff, more power to you!

More often, I talk to developers who recoil from the dogmatic pronouncements of agile proponents.

Software developers are a funny bunch. We are prone to seeing the world in very black or white, zero or one terms, and we generally have finely tuned bullshit filters. We prefer a world that is rational, measurable and repeatable to one where truth is determined by politics, personality and political correctness. When confronted with admonishments to pair program, write unit tests, use Pivotal Tracker or pat your head while rubbing your belly, we ask, "Why?" All too often, agilistas respond by implying that you can't possibly succeed in software development without doing all these things, and more: this is just padawan stuff, just wait 'till you become a full-fledged Jedi! At this point, the bullshit filter is engaged and anything that smacks of "agile" is permanently tagged with bozo, to be called up later when a target for ridicule is needed.

That's a shame, because agile methodologies like XP and Scrum really aren't about writing software, but about managing complex projects where the goal is to build something unique and novel. And it's a rare software project that doesn't have uncertain requirements, technical risk, deadlines and limited budget. Software project planning and management is far too often dominated by the politics, personality and political correctness that software developers eschew. The core idea of agile methodologies is to turn project planning and management into something more rational, measurable and repeatable. Blanket prescriptions that you must write code a certain way, use a particular tool or hold certain kinds of meetings aren't helpful; in fact, they can be actively harmful to a functioning development team.

Mike Cohn (the author of one of my favorite books, Agile Estimating and Planning) made a New Year's resolution to "Make recommendations not rules". Mike lays out his view of the core rules that make a software development team "agile" in his eyes. It's a short list, just five points, but it gets at the heart of good project management, whether you call it agile or not. "Beyond that, it’s much more about recommendations," Mike states, and I agree.

If you're an agile proponent, try to keep in mind that each team's pain is unique, and there are many different paths to success. User stories or planning poker may be the shiny new candy to you, but most people just want to get their work done. Pushing strange new techniques on people and organizations that are unready or unreceptive is ineffective at best and counterproductive at worst. Making sure the right people are having the right conversations at the right time is at the heart of any successful project. Agile methodologies like XP and Scrum are frameworks for making this happen, but they're not the only way. Avoid agile purity tests, adapt to local circumstances and prefer recommendations over rules.

Thursday, December 8, 2011

Getting more from NSLog()

In a series of recent blog posts, John Muchow of iOS Developer Tips shows how to create your own wrapper around NSLog() to add useful debugging information to your log output like file name and line number:

Some great tips and tricks, check it out!

Tuesday, December 6, 2011

Objective-C Tuesdays: more NSArray sorting

Welcome to another Objective-C Tuesdays. Last week, we looked at sorting C arrays and NSArrays. Today, we will continue looking at sorting NSArrays using NSSortDescriptors.

As we saw last week, the sorting methods of NSArray require you to specify a comparator in one form or another. When sorting an NSArray of simple objects like NSStrings or NSDates, the comparators are usually pretty simple to write and common objects often have useful comparator methods like -caseInsensitiveCompare: and -localizedCompare:.

When sorting NSArrays of more complex objects, writing comparators is often more tedious and error-prone. Here's the interface for simple Person class:
// Person.h
@interface Person : NSObject

@property (strong) Address *address;
@property (strong) NSDate *birthdate;
@property (copy) NSString *firstName;
@property (copy) NSString *lastName;

@end

And here's the Address class used by Person:
// Address.h
@interface Address : NSObject

@property (copy, nonatomic) NSString *street;
@property (copy, nonatomic) NSString *city;
@property (copy, nonatomic) NSString *state;
@property (copy, nonatomic) NSString *country;
@property (copy, nonatomic) NSString *postalCode;

@end

If we have an NSArray of Person objects, we may want to sort them in country, lastName, firstName order. Here's one way to do that, using a comparator block:
// sort Person objects by lastName, firstName
Person *frodo = [Person new];
[frodo setFirstName:@"Frodo"];
[frodo setLastName:@"Baggins"];
// ...
[[frodo address] setCountry:@"Shire"];

Person *bilbo = [Person new];
[bilbo setFirstName:@"Bilbo"];
[bilbo setLastName:@"Baggins"];
// ...
[[bilbo address] setCountry:@"Shire"];

Person *legolas = [Person new];
[legolas setFirstName:@"Legolas"];
[legolas setLastName:@"Greenleaf"];
// ...
[[legolas address] setCountry:@"Mirkwood"];

NSArray *people = [NSArray arrayWithObjects:frodo, bilbo, legolas, nil];
NSArray *sortedPeople = [people sortedArrayUsingComparator:^(id item1, id item2) {
Person *person1 = item1;
Person *person2 = item2;

// NSComparisonResult is a typedef for int
NSComparisonResult result = [[[person1 address] country] compare:[[person2 address] lastName]];
if (result) {
return result;
}

result = [[person1 lastName] compare:[person2 lastName]];
if (result) {
return result;
}

result = [[person1 firstName] compare:[person2 firstName]];
if (result) {
return result;
}

return NSOrderedSame; // NSOrderedSame == 0
}];
// sortedPeople contains:
// Legolas Greenleaf (Mirkwood)
// Bilbo Baggins (Shire)
// Frodo Baggins (Shire)

The general pattern of a multi-field comparator is simple: check each field in turn, stop and return the comparison result if non-zero; if all fields are equal, return zero (or NSOrderedSame to be more descriptive). This quickly becomes tedious when you have many fields to sort by or you need to dig down into child or grandchild objects for fields.

Fortunately, there's an easier way to do this. NSArray has a method called -sortedArrayUsingDescriptors: that takes an array of NSSortDescriptor objects. Each NSSortDescriptor specifies a key path and sort direction (ascending or descending). The order of NSSortDescriptors in the array determines the precedence of each field. If you're not familiar with Key Value Coding (KVC), you may not have encountered key paths before. KVC is similar reflection in Java and other dynamic languages. KVC allows you to get and set fields on an object using the field names as strings, called keys. To access fields on child objects, you use keys separated by dots to form a key path; KVC knows how to drill down your object graph and access fields on child objects. There are a lot of interesting things you can do with KVC, but today we will stick to building an array of NSSortDescriptors:
NSSortDescriptor *byCountry = [NSSortDescriptor sortDescriptorWithKey:@"address.country" 
ascending:YES];
NSSortDescriptor *byLastName = [NSSortDescriptor sortDescriptorWithKey:@"lastName"
ascending:YES];
NSSortDescriptor *byFirstName = [NSSortDescriptor sortDescriptorWithKey:@"firstName"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:byCountry, byLastName, byFirstName, nil];

Notice that the byCountry sort descriptor uses the key path @"address.country": it will first get the value of the address property of the Person object, then get the country property of the address. Key paths can be as deep as your object graph.

Using the array of sort descriptors is easy:
NSArray *sortedPeople = [people sortedArrayUsingDescriptors:sortDescriptors];
// sortedPeople contains:
// Legolas Greenleaf (Mirkwood)
// Bilbo Baggins (Shire)
// Frodo Baggins (Shire)

This certainly makes creating complex sort criteria much easier, and you're not limited to the default comparator for a field. You can specify a selector for a comparator method on the field this way:
// specify a method to call on the lastName object
NSSortDescriptor *byLastName = [NSSortDescriptor sortDescriptorWithKey:@"lastName"
ascending:YES
selector:@selector(caseInsensitiveCompare:)];

Or for more specialized comparisons, you can pass in a NSComparator block this way:
// sort descriptor using length of last name
NSSortDescriptor *byLastNameLength = [NSSortDescriptor sortDescriptorWithKey:@"lastName"
ascending:YES
comparator:^(id item1, id item2) {
NSString *lastName1 = item1;
NSString *lastName2 = item2;
// cast result to NSComparisonResult so that the
// compiler infers the correct return type
return (NSComparisonResult) ([lastName1 length] - [lastName2 length]);
}];

Specifying complex sort orders with NSSortDescriptors is the type of higher level, declarative code that is easy to write, easy to read and easy to maintain, and in most cases you should consider using NSSortDescriptor rather than writing your own comparator methods, functions or blocks.

Next time, we will look at sorting NSMutableArrays in place, rather than producing a sorted copy like the various -sortedArray methods.

Monday, December 5, 2011

iPhone owners upgrading to iOS 5 rapidly

Chart: OS is 'at least this' -- All devicesLess than two months after the release of iOS 5, nearly half of all iOS device owners have upgraded. Marco Arment, the developer of Instapaper (one of my favorite and frequently used apps), periodically releases iOS metrics he gathers from Instapaper users detailing the breakdown of iOS versions and iOS device types.

The tl;dr conclusion: nearly 99% of Instapaper users have iOS 4.0 or later, and nearly 95% have an iPhone 3GS-class processor or better. This jibes with what we see at Able Pear. We're planning to only support iOS 4.0 and later for all future app releases.

This is one of the things that Apple really does right with iOS. iPhone, iPad and iPod touch users upgrade their devices pretty rapidly; with iOS 5 allowing you to upgrade the OS directly on the device without connecting to iTunes, this will become that much easier and adoption of the latest OS versions will only improve in the future. As an app developer, there are pluses and minuses to Apple's tight control, but as an iOS user, this is a very solid plus -- upgrades are easy and developers rapidly support the latest iOS goodies rather than target some very old lowest common denominator OS version.

Check out the complete breakdown in More iOS device and OS version stats from Instapaper.

Wednesday, November 30, 2011

Great Geek Gift: Making Embedded Systems

Making Embedded SystemsIf you're looking for a great gift idea for that geek in you life (or for yourself :-) and you're interested in computer hardware as well as software, check out Making Embedded Systems: Design Patterns for Great Software by Elecia White. I had the good fortune to work with Elecia on a project last year and she's a top notch engineer -- and now an O'Reilly author. In her new book Making Embedded Systems, Elecia covers everything you need to know to get started building and programming embedded devices: system architecture, reading data sheets, debugging hardware and software, IO and timers, handling interrupts, peripherals and power consumption. If you're part of the Maker Faire/Arduino/Circuit Cellar hardware hacking community, or interested in learning about it, I highly recommend you check it out! Like most O'Reilly books, it's available as a printed book or in various e-book formats that work great with Kindle and iPads.

Tuesday, November 29, 2011

Objective-C Tuesdays: sorting arrays

Good news everyone! Objective-C Tuesdays is back! We left off a few weeks ago talking about techniques for inserting and removing items in arrays. Today we will cover sorting C arrays as well as NSArrays and NSMutableArrays.

Sorting C arrays with qsort()
The C standard library includes only one built-in way to sort C arrays: the qsort() function. qsort() is an implementation of the quicksort algorithm, a good general purpose sorting algorithm. qsort() sorts an array in place.

The qsort() prototype looks like this:
qsort(void *array, size_t itemCount, size_t itemSize,
int (*comparator)(void const *, void const *));

If you're not experienced using function pointers in C, the declaration of qsort() will look confusing. That's because declaring a C function pointer type is confusing. I'll use a typedef to make things easier to understand:
// alternate declaration of qsort using a typedef:
typedef int (*Comparator)(void const *, void const *);

qsort(void *array, size_t itemCount, size_t itemSize,
Comparator comparator);

Function pointers are declared in the same way that functions are declared in C, except they have a * before the function name like other pointer variables do. But there's one hitch. In a function pointer declaration, the * is ambiguous; by default, C will assume the * is part of the return type of the function. So when you declare a function pointer, you need a set of parentheses around the * and the function name in order to clue in the compiler.
// declare a function returning a pointer to an int
int *returnAPointerToSomeInt(void);
// which is interpreted as:
// (int *)returnAPointerToSomeInt(void);

// declare a pointer to a function returning an int
int (*returnSomeInt)(void);

Now that we've cleared that up, let's look at the declaration of qsort() again.
typedef int (*Comparator)(void const *, void const *);

qsort(void *array, size_t itemCount, size_t itemSize,
Comparator comparator);

The first three parameters of qsort() specify the array to sort, the count of items in the array and the size (in bytes) of a single item. Note that the array is of type void *, which allows us to pass any type of C array into qsort().

The last parameter is the comparator function.
typedef int (*Comparator)(void const *item1, void const *item2);

The comparator takes pointers to two items from the array and returns a negative number if item1 belongs before item2, a positive number if item1 belongs after item2 and zero if the two items are equal (or have equivalent ordering). This style of comparator function is used in many languages for sorting. I think of the items positioned on a number line when trying to understand a comparator:

item1 <=====<< item2
<-+------+-----+------+------+->
-2 -1 0 1 2

item2 >>=====> item1
<-+------+-----+------+------+->
-2 -1 0 1 2

When item1 belongs before item2, the comparator function will return a negative number; when item1 belongs after item2, the comparator returns a positive number. This relationship is the difference between item1 and item2, or item1 - item2.

The C standard library doesn't include many comparator functions, but they're easy to write. Here's an example of a comparator for ints to sort them in natural order:
int compareInts(void const *item1, void const *item2) {
int const *int1 = item1;
int const *int2 = item2;
return *int1 - *int2;
}

We create local variables int1 and int2 since a void pointer will automatically convert to a typed pointer in C, and we know that qsort() will actually be giving us pointers to ints. The two parameters are also const, so we can't modify the int values that the items point to (which would cause qsort() to go haywire). Then we can simply return the difference between the two int values to determine their sort order. We could do this in one line using casts and parentheses:
int compareInts(void const *item1, void const *item2) {
return *( (int const *) item1) - *( (int const *) item2);
}

Either way, now we can use our compareInts() function to sort an array of ints:
int array[6] = { 42, 17, 57, 19, 11, 5 };

qsort(array, 6, sizeof(int), compareInts);
// array now contains 5, 11, 17, 19, 42, 57

Now suppose we wanted to sort our array in reverse order? We would still use qsort() to do the job, but employ a different comparator function. Here is compareIntsReversed():
int compareIntsReversed(void const *item1, void const *item2) {
int const *int1 = item1;
int const *int2 = item2;
return -(*int1 - *int2);
// or simply return *int2 - *int1;
}

By reversing the sign of the comparator's return value, you can reverse the order of sorting.
int array[6] = { 42, 17, 57, 19, 11, 5 };

qsort(array, 6, sizeof(int), compareIntsReversed);
// array now contains 57, 42, 19, 17, 11, 5

The qsort() function is very flexible. You can sort arrays of complex types as easily as arrays of ints. To sort an array of C strings in lexicographic order, use the strcmp() function from the C standard library.
char const *array[3] = { "red", "green", "blue" };

qsort(array, 3, sizeof(char const *), strcmp);
// array now contains "blue", "green", "red"

Sorting an array of CGPoints, first write a comparator:
int compareCGPoints(void const *item1, void const *item2) {
struct CGPoint const *point1 = item1;
struct CGPoint const *point2 = item2;

if (point1->x < point2->x) {
return -1;
} else if (point1->x > point2->x) {
return 1;
}

if (point1->y < point2->y) {
return -1;
} else if (point1->y > point2->y) {
return 1;
}

return 0;
}

Notice that we first compare the X coordinates of the points and only check the Y coordinates if the X coordinates are equal. This is a common pattern when sorting over multiple fields in a struct. Here's an example of the CGPoint comparator in action:
struct CGPoint pointArray[4] = {
{ 4.0f, 3.0f },
{ 2.0f, 1.0f },
{ 4.0f, 1.0f },
{ 2.0f, 3.0f }
};
qsort(pointArray, 4, sizeof(struct CGPoint), compareCGPoints);
// pointArray now contains:
// { 2.0f, 1.0f }
// { 2.0f, 3.0f }
// { 4.0f, 1.0f }
// { 4.0f, 3.0f }


Other C sorting functions
For most common sorting jobs, qsort() it a reasonable choice, and it's the only choice that's included in the C standard library. OS X and iOS also include a couple of other sorting functions worth mentioning: heapsort() and mergesort(), which have the same parameters as qsort() and are detailed on the qsort() man page. heapsort() is slower than qsort() but uses a limited amount of memory while sorting, whereas qsort() uses recursion and can potentially overflow the stack when sorting huge arrays. mergesort() can be significantly faster than qsort() when the array is mostly in sorted order already, but is significantly slower when the array is in random order.

Sorting an NSArray
Objective-C provides a number of ways to sort an NSArray. Because NSArray objects are immutable, all the sorting methods on NSArray return a new sorted NSArray object and leave the original one unchanged. The most basic sorting method is -sortedArrayUsingFunction:context:, which is similar to sorting a C array with qsort(). The full method declaration looks like this:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator 
context:(void *)context

The first parameter is a pointer to a comparator function. As we did for qsort(), I'll rewrite the method declaration using a typedef for the function pointer to make it a little easier to read:
typedef NSInteger (*Comparator)(id item1, id item2, void *context);

- (NSArray *)sortedArrayUsingFunction:(Comparator)comparator
context:(void *)context

The comparator function for NSArray sorting has a few differences from the qsort() one. It returns an NSInteger, which is simply a typedef for int. Instead of two items of type void const *, it takes two items of type id since NSArrays can only hold object types. And finally, there's an extra context parameter, a void pointer that allows you to pass extra information to the comparator if you need to (but you can safely ignore it if you don't need it).

Let's write a comparator function that orders NSStrings by their length.
static NSInteger compareStringsByLength(id item1, id item2, void *context) {
return [item1 length] - [item2 length];
}

Since we can send any message to a variable of type id, we don't even need casts or intermediate variables here. (Of course, we'll get a runtime error if we put the wrong type of objects into our array, but comparators for qsort() have the similar problems.)

And now let's see it in action:
NSArray *array = [NSArray arrayWithObjects:@"Florida", 
@"Texas", @"Mississippi", @"Delaware", nil];

NSArray *sortedArray = [array sortedArrayUsingFunction:compareStringsByLength
context:NULL];
// sortedArray contains:
// @"Texas"
// @"Florida"
// @"Delaware"
// @"Mississippi"

Now let's use the context parameter to make it easy to switch between normal and reversed sort order. We can pass a pointer to any kind of data we want, so we will use a pointer to a BOOL, where a YES value means reversed and a NO value means normal ordering.
NSInteger compareStringsByLength(id item1, id item2, void *context) {
BOOL *reversed = context;
NSInteger order = [item1 length] - [item2 length];
if (*reversed) {
return -order;
} else {
return order;
}
}

Now we need to pass something to the context parameter when we call -sortedArrayUsingFunction:context:
NSArray *array = [NSArray arrayWithObjects:@"Florida", 
@"Texas", @"Mississippi", @"Delaware", nil];

BOOL reversed = YES;
NSArray *sortedArray = [array sortedArrayUsingFunction:compareStringsByLength
context:&reversed];
// sortedArray contains:
// @"Mississippi"
// @"Delaware"
// @"Florida"
// @"Texas"

Note that we use the & operator to pass the address of the reversed variable as the context.

If you target iOS 3.2, OS X 10.6 or later, you can use the block version, -sortedArrayUsingComparator:. Blocks make one-off comparator functions easier to read and understand by putting the comparator definition right along side the sort method call. We can rewrite our example this way:
NSArray *array = [NSArray arrayWithObjects:@"Florida", 
@"Texas", @"Mississippi", @"Delaware", nil];

BOOL reversed = YES;
NSArray *sortedArray = [array sortedArrayUsingComparator:^(id item1, id item2) {
NSInteger order = [item1 length] - [item2 length];
if (reversed) {
return -order;
} else {
return order;
}
}];
// sortedArray contains:
// @"Mississippi"
// @"Delaware"
// @"Florida"
// @"Texas"

Since a block copies the value of variables like reversed in the enclosing scope at the time it's created, there's no need for a second context parameter to -sortedArrayUsingComparator:. Blocks are really handy, but if you find yourself writing the same comparator block in multiple places in your code, you might be better off using a plain old comparator function and -sortedArrayUsingFunction: instead to prevent duplicate code, in keeping with the DRY principle. (Or you might consider how to restructure your code so that sorting is defined in only one place.)

Since items in an NSArray are all objects, very often the items themselves have a useful comparator method. When this is the case, the -sortedArrayUsingSelector: method is very handy. NSArrays of NSStrings are very common, as is the need to sort in a case-insensitive manner. Using NSString's -caseInsensitiveCompare: method, we can sort this way:
NSArray *tagNames = [NSArray arrayWithObjects:@"H1", 
@"body", @"A", @"Head", nil];

NSArray *sortedTagNames = [tagNames sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
// sortedTagNames contains:
// @"A"
// @"body"
// @"H1"
// @"Head"

There's one more interesting way to sort an NSArray: we'll look at the -sortedArrayUsingDescriptors: method and the NSSortDescriptor class next week.

Wednesday, October 5, 2011

Steve Jobs


I lived in Palo Alto for many years, and would see Steve Jobs around town from time to time. I'd see him buying flowers at Stanford Florist, shopping for organic lentils in Whole Foods, talking on his iPhone outside Evvia before meeting people for dinner or strolling with his wife past Fraiche on a sunny afternoon.

And I've followed his career from the beginning, starting when I was a nerdy kid into computers. I read all about the Lisa, Steve's first baby, named after his daughter and now long forgotten and I followed the launch of its more successful sibling, the Macintosh. I was not fortunate enough to be a Mac owner in those early days but some of my friends had them and I always loved the little Mac toasters. I was primarily a Windows user for many years, but there was always something about the design of the Mac that was so clean and appealing, even years after Steve was forced out of Apple.

I was in college when he started NeXT. The black NeXT cube was so cool, so fascinating. While I had hoped that NeXT would be successful, unfortunately for too many people, myself included, the NeXT was too different, too expensive, my existing software and hardware wasn't compatible. Computing in the late 80's was very different, and the network effect of Wintel hardware and software compatibility drove even die hard Mac fans to buy PCs.

NeXT struggled. I was sad when they ceased producing that sleek black cube. They concentrated on selling the NeXTStep OS and development tools, with limited success at best. I wonder what it must have been like to have been so successful with Apple then to struggle so much with NeXT.

These years were also a struggle for Apple. Their biggest challenge was simply persisting in the face of the Windows juggernaut, but many of Apple's problems were self-inflicted. A decade of building atop Steve's original Macintosh foundation had left Apple with the OS equivalent of a house of cards. Apple recognized this, but their various projects to produce a new Macintosh OS never amounted to anything and their attempt to build a new class of product, the Newton, was overly expensive, marginally useful and widely lampooned.

I owned one of the first Newtons. I used it for about a year as my address book and calendar, but eventually gave it up in frustration and went back to a paper daily planner. It was a sad time for fans of Apple.

Then Apple acquired NeXT. NeXT had a modern operating system that nobody much wanted, and Apple made computers that needed a modern OS. And Steve came back to Apple as an advisor. And suddenly Apple didn't look so doomed. If you have the time, I recommend you watch Steve's Q&A session at WWDC 1997. It's his first WWDC after coming back to Apple. What comes through to me is that Steve clearly loves this stuff, and that he has his sights clearly focused on creating the best experience for the Mac user, not on some cool technology or selling more boxes to IT managers or making developer's lives easier. If you watch the Q&A, you'll see some discussion about OpenDoc and that it was killed. OpenDoc was a compound document technology that was supposed to compete with Microsoft's OLE. But OpenDoc was complex, buggy and late and one of the first things Steve did on returning to Apple was kill it. This was a big deal to Macintosh developers who had spent a lot of time and effort rewriting their apps to support OpenDoc, but Steve clearly saw that it didn't matter: most Mac users didn't care how their documents were stored, and that OpenDoc didn't bring those users much benefit. I think it's that keen sense, that focus on the user that served Steve so well in his career, but especially during his second tenure at Apple.

The history of Steve's second coming is now legend. But let's not minimize the audacity of Apple's most successful products. The iPod seemed a pretty random sideline for a computer company like Apple. Year after year, model after model, Apple relentlessly improved the iPod. After the disappointing Newton, I hadn't owned another Apple product until the iPod. It was a kind of gateway drug to Apple gear. A shiny 13 inch titanium MacBook Pro followed a couple years later. It was a secondary computer for traveling, but I began to use it more and more and my Windows machine less and less.

When the first iPhone was announced, I was initially lukewarm. Certainly a bold, audacious move by Apple, but it didn't grab me immediately. With so much buzz and enthusiasm building before the launch I went to Apple's site to take a look at the iPhone product info. After watching the iPhone demo video, slickly produced in the best Apple style, I came around and found myself in the Palo Alto Apple Store on launch day a couple of weeks later.

In my career writing software, I've always gotten the most satisfaction out of producing things that help people in their daily lives. I can only imagine how it must feel to be the leader of a team that produces such a revolutionary product loved by so many. Steve must have been insanely proud.

Industry and media pundits love to cast things as a contest: Windows versus Mac, Android versus iPhone, but to his credit and our delight, Steve Jobs could see past that. His final creation, the iPad, is so beloved by so many people, most especially by "your mom", those ordinary people for whom computers hold no intrinsic fascination. I think it's truly Steve's ultimate creation.

Yet remember that the iPad is only a year and a half old. We all know his health has been challenging, but it seems too soon to lose Steve. There's yet so much more to do, so many delightful machines to create. We will look to the folks at Apple to finish what he started.

Steve did what he loved up until the very end. If only we all could be that lucky.

Wednesday, August 31, 2011

"Where can we take the customer?"

And, one of the things I’ve always found is that you’ve got to start with the customer experience and work backwards for the technology. You can’t start with the technology and try to figure out where you’re going to try to sell it. And I made this mistake probably more than anybody else in this room. And I got the scar tissue to prove it. And I know that it’s the case.

...

And as we have tried to come up with a strategy and a vision for Apple, it started with “What incredible benefits can we give to the customer? Where can we take the customer?” Not starting with “Let’s sit down with the engineers and figure out what awesome technology we have and then how are we going to market that?” And I think that’s the right path to take.

- Steve Jobs at WWDC 1997

 

Wednesday, August 3, 2011

Developing on Android vs iOS

If you're building mobile apps these days, you're probably watching the Android market closely if you're not already developing for it. With reports coming in weekly that Android activations are growing faster than ever, simple extrapolation will tell you that soon, there will be more Android devices on that planet than people. Many successful mobile devs, most of them currently focused on Apple's iOS platform, are seriously investigating the Android platform and starting to port their apps. A few adventurous developers have written some thoughtful articles describing their experience and comparing Android and iOS development.

Nick Farina of Spotlight Mobile describes his impressions of Android garnered while porting his Meridian app from iOS. He covers the good and the bad of each platform in technical detail, and it's a good read if you're a developer moving from iOS to Android or vice versa. Nick approaches Android with the open mind of a developer who has worked on many platforms—the first version of Meridian was launched on Windows Mobile. Nick sums up his philosophy:
We decided it was important to keep the native stuff native, and to respect each platform’s conventions as much as possible.
...
So, we rolled up our sleeves, downloaded the Android SDK, and got to work
Back in March, Geoffrey Goetz of GigaOM gave his comparison of development on the two platforms. Goetz gives a high level summary, including a somewhat shallow summary table highlighting the platform differences. This is probably most useful if you're an executive who manages mobile developers, but is worth a quick read if you're a developer who's new to one of the two platforms. Goetz mentions Apple's WWDC videos and the Stanford iOS development course on iTunesU as a big plus for the developer learning experience on iOS and I have to agree: both are excellent resources. Goetz fails to mention that videos of many Google IO sessions covering Android are also freely available, though I can't say if they have the same high quality as Apple's iTunesU offerings.

Samuel Sutch gives another iOS developer's perspective on Android in a post on Google+. He sums up his take on Android in the opening paragraph:
The Android API requires it's users be really good programmers. Android abstractions are much more in-depth, (drawn out, forced, and complicated) than the equivalent iOS abstractions. However "Intents" are great once you get them.
I also recommend the discussion of the post on Hacker News.

Finally, if you're thinking about jumping on the Android bandwagon, keep in mind Ben Duchac's post, Why My Mom Bought an Android, Returned It, and Got an iPhone. Android can be a challenging experience for non-technophiles. I suspect that because Apple has positioned the iPhone and iPad as premium devices, they've captured a large fraction of consumers who are interested and engaged in their mobile experience, and iOS app sales have benefitted from that. Conversely, non-techie Android owners are less interested in using their devices to the fullest and more sensitive to price.

If you want to make money on app sales, I wouldn't bet the farm on Android right now. If you're targeting a technophilic audience, you probably want to be on both Android and iOS. If you're pursuing app sales to a mass market, I would recommend iOS first and Android as an optional second right now. However, if you have an existing product or service with a supplemental mobile app, you should definitely be planning to offer it on both iOS and Android.

Tuesday, August 2, 2011

Objective-C Tuesdays: more about dynamic arrays

Welcome back to Objective-C Tuesdays. Last time we were talking about dynamic arrays in C and NSMutableArray in Objective-C. We'll continue looking at both today.

We looked at using malloc() or calloc() to dynamically allocate a block of memory that you can treat like an array. This is very useful when you don't know the number of items you need to store until run time or when you need the array to exist longer than the current function call.

But what happens when you need to grow or shrink the memory block? Well, the straightforward way would be to allocate a new memory block, copy over the contents and free the old block. You use the memcpy() function in the C standard library to do the copying.
// resizing a memory blockint *lotteryNumbers = malloc(sizeof(int) * 6);if ( ! lotteryNumbers) {  // memory allocation failed  exit(EXIT_FAILURE);}lotteryNumbers[0] = 7;// ...lotteryNumbers[5] = 29;// now we need to store more numbers// so allocate a bigger memory blockint *biggerMemoryBlock = malloc(sizeof(int) * 12);if ( ! biggerMemoryBlock) {  // memory allocation failed  exit(EXIT_FAILURE);}// copy lotteryNumbers into biggerMemoryBlockmemcpy(biggerMemoryBlock, lotteryNumbers, sizeof(int) * 6);// free old memory blockfree(lotteryNumbers);// replace old memory block pointer with new onelotteryNumbers = biggerMemoryBlock;lotteryNumbers[6] = 31;// ...lotteryNumbers[11] = 49;
When copying blocks of memory, be careful to specify the correct size in bytes. In the example above, we use the same expression to calculate the size, sizeof(int) * 6 for both the original call to malloc() and to memcpy(). Using the sizeof operator like this serves two purposes. It makes the code portable, since the size of an int may be different on some systems (it's four bytes on iOS). More importantly, it tells anyone reading the code that you intended to allocate six ints. If you had specified simply malloc(24) or even malloc(6 * 4), your intention is not as clear.

Resizing a memory block with realloc()
Allocating a larger or smaller memory block and copying over the contents works perfectly, but it is tedious. Fortunately, the C standard library includes the realloc() function which does exactly this for you in one function call. It can operate on any memory block allocated with malloc() or calloc(). In addition, because it's part of the standard library, realloc() can do things that you can't: it will try to grow or shrink the memory block in place, skipping the copy step. Sometimes the memory manager will give you a block of memory somewhat bigger than you requested, other times the memory area after your memory block is currently unused. Because realloc() is privy to the implementation details of the memory manager, it can figure out when it's safe to grow your memory block in place.

The realloc() function returns a pointer to either the original memory block or a new memory block on success, or NULL if memory allocation fails. If the new memory block is bigger than the original, the new items will be set to zero, just as if you allocated the memory block with calloc(). Like malloc(), realloc() requires you to calculate the size of the memory block in bytes.
// using realloc()int *lotteryNumbers = malloc(sizeof(int) * 2);if ( ! lotteryNumbers) {  // out of memory  exit(EXIT_FAILURE);}lotteryNumbers[0] = 7;lotteryNumbers[1] = 11;// ...int *resizedLotteryNumbers = realloc(lotteryNumbers, sizeof(int) * 6);if ( ! resizedLotteryNumbers) {  // out of memory but lotteryNumbers memory block  // is still valid and unchanged  exit(EXIT_FAILURE);}// replace the old pointer with the new onelotteryNumbers = resizedLotteryNumbers;lotteryNumbers[2] = 19;// ...
If realloc() fails, it leaves the original memory block unchanged. Just as for calloc() and malloc(), you must remember to call free() on the memory block when you're done with it.

Inserting items into a C array
It should be obvious by now how to add items to the end of a C array (if it's big enough) or a dynamically allocated memory block that you've enlarged using realloc(). But how do you insert an item at the beginning or middle of an array while keeping all of the current items? There's no magic here, you have to shift items to higher indices to make space for the new one.
// insert an item at the start of a C arrayint lotteryNumbers[6] = { 11, 17 }; // has room for six items// shift current items uplotteryNumbers[2] = lotteryNumbers[1];lotteryNumbers[1] = lotteryNumbers[0];// array now holds { 11, 11, 17 }lotteryNumbers[0] = 7; // insert new item// array now holds { 7, 11, 17 }
Note that you need to shift items starting at the end of the array, otherwise you'll overwrite items you want to preserve. Obviously writing a line of code for each item you need to shift isn't a practical solution. You might be tempted to use the memcpy() function to shift items, but memcpy() has an important restriction: the source and destination memory blocks may not overlap. (This is because memcpy() may copy items front to back and thus overwrite items you want to preserve.) The memmove() function is meant to be used when the memory blocks overlap and will always shift items in the correct order to preserve the contents.
// using memmove() to insert an itemint lotteryNumbers[6] = { 11, 17 }; // has room for six items// shift current items upint *destination = lotteryNumbers + 1;int *source = lotteryNumbers;size_t size = sizeof(int) * 2;memmove(destination, source, size);// array now holds { 11, 11, 17 }lotteryNumbers[0] = 7; // insert new item// array now holds { 7, 11, 17 }
Because memmove() can operate on any kind of array or memory block, we need to do some pointer arithmetic to determine the source and destination addresses and the number of bytes to move. Again, the sizeof operator helps make our intentions clear. An alternate way specify the source and destination addresses is to use the address of operator (&) on indexed items in the array.
// determine source and destination using address of// ...int *destination = &lotteryNumbers[1];int *source = &lotteryNumbers[0];size_t size = sizeof(int) * 2;memmove(destination, source, size);// array now holds { 11, 11, 17 }// ...
These are equivalent notations and choosing one over the other is a matter of style.

You can use this technique to insert items into both C arrays and dynamically allocated memory blocks. Just make sure that there is enough space to move items around and that you don't write items past the end of your array or memory. As with all things in C, there is no safety net. To remove items from the beginning or middle of an array, follow the same procedure using memmove(), only shift items down and intentionally overwrite the items you want to delete. I'll leave this one as an exercise for the reader ☺.

Inserting items into an NSMutableArray
While using memmove() to shift items around isn't too terrible, the equivalent operations using NSMutableArray are naturally much more direct. To insert a single item at a particular index, you naturally use -insertObject:atIndex:
// inserting an item into an NSMutableArrayNSMutableArray *colors = [NSMutableArray arrayWithObjects:@"red",                                                           @"green",                                                           @"blue",                                                           nil];[colors insertObject:@"orange" atIndex:1];// colors now holds "red", "orange", "green" and "blue"
Inserting multiple items at one time is trickier. With the -insertObjects:atIndexes: method, you can insert items from an NSArray into your NSMutableArray. The tricky part here is that you need to also pass in an NSIndexSet (or NSMutableIndexSet) along with the array. Here's how you would insert an NSArray containing one item.
// inserting an item into an NSMutableArrayNSMutableArray *colors = [NSMutableArray arrayWithObjects:@"red",                                                           @"green",                                                           @"blue",                                                           nil];NSArray *newColors = [NSArray arrayWithObject:@"orange"];NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:1];[colors insertObjects:newColors atIndexes:indexSet];// colors now holds "red", "orange", "green" and "blue"
You must make sure that there is an index in the NSIndexSet for each item you are inserting. If you want to insert the new items all in one spot, the +indexSetWithIndexesInRange: method of NSIndexSet makes this easy.
// inserting multiple items into an NSMutableArrayNSMutableArray *colors = [NSMutableArray arrayWithObjects:@"red",                                                           @"green",                                                           @"blue",                                                           nil];NSArray *rainbowColors = [NSArray arrayWithObjects:@"orange",                                                    @"yellow",                                                    @"indigo",                                                    @"violet",                                                    nil];NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 4)];[colors insertObjects:rainbowColors atIndexes:indexSet];// colors now holds "red", "orange", "yellow", "indigo", "violet", "green" and "blue"
Sometimes you want to insert different items at different points in your NSMutableArray. This is where -insertObjects:atIndexes: really shines. You'll want to use NSMutableIndexSet to create the index set in this case. Lets modify the previous example to insert the colors in standard rainbow order.
// inserting multiple items into an NSMutableArrayNSMutableArray *colors = [NSMutableArray arrayWithObjects:@"red",                                                           @"green",                                                           @"blue",                                                           nil];NSArray *rainbowColors = [NSArray arrayWithObjects:@"orange",                                                    @"yellow",                                                    @"indigo",                                                    @"violet",                                                    nil];NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];[indexSet addIndex:1];[indexSet addIndex:2];[indexSet addIndex:5];[indexSet addIndex:6];[colors insertObjects:rainbowColors atIndexes:indexSet];// colors now holds "red", "orange", "yellow", "green", "blue", "indigo" and "violet"
To figure out the correct indices can be tricky. Inside the -insertObjects:atIndexes: method, new items will be inserted one at a time, starting with the lowest index in the index set. While inserting a group of items is a very powerful capability of NSMutableArray, often times I think it's easier and faster to write correct code that uses -subarrayWithRange: to break the items up into contiguous blocks before inserting them, or even to use -insertObject:atIndex: repeatedly to insert items one by one. But when it is straightforward to figure out the index set, -insertObjects:atIndexes: makes your code very succinct.

Next time, we'll look at sorting C arrays, NSArrays and NSMutableArrays.