Posterous theme by Cory Watilo

Filed under: Objective-c

Generating AES256 keys from a password/passphrase in ObjC

From an upcoming app that needs to encrypt your data using a passphrase, using industry standard methods:

#import <CommonCrypto/CommonKeyDerivation.h>

...

// Makes a random 256-bit salt
- (NSData*)generateSalt256 {
    unsigned char salt[32];
    for (int i=0; i<32; i++) {
        salt[i] = (unsigned char)arc4random();
    }
    return [NSData dataWithBytes:salt length:32];
}

...

// Make keys!
NSString* myPass = @"MyPassword1234";
NSData* myPassData = [myPass dataUsingEncoding:NSUTF8StringEncoding];
NSData* salt = [self generateSalt256];

// How many rounds to use so that it takes 0.1s ?
int rounds = CCCalibratePBKDF(kCCPBKDF2, myPassData.length,
    salt.length, kCCPRFHmacAlgSHA256, 32, 100);

// Open CommonKeyDerivation.h for help
unsigned char key[32];
CCKeyDerivationPBKDF(kCCPBKDF2, myPassData.bytes, myPassData.length,
    salt.bytes, salt.length, kCCPRFHmacAlgSHA256, rounds, key, 32);
NSData* keyData = [NSData dataWithBytes:key length:32];

My App Manifesto: Syncing + Dropbox + YAML = Awesome

I couldn’t decide what to title this post, so i’m giving you choices:

  • Apps that sync
  • Apps, Dropbox, YAMLKit, and power users
  • Dropbox + YAML + Syncing apps = Happy power users
  • Please use Dropbox + YAML and make your App sync
  • My Syncing Apps Manifesto: Dropbox + YAML = Awesome

Anyway, here’s my point: Too many iPhone apps have reviews with a common complaint: It’d be great, if only it would sync.

You see, there are a lot of people these days who have more than one iDevice. Here’s a common situation: Jim has an iPad which he uses at home, an iPhone which he uses on the train to work, and a Mac/PC at work. He’d love to use the same app on all of those, with his data synced elegantly.

Dropbox vs iCloud

Day one gets it right with their diary app: everything is synced to iCloud or Dropbox, there are different versions of the app for iPhone, iPad, and the Mac, and they all work to the strengths of each platform. Eg you can type on the Mac/iPhone, and read on the iPhone, or even take short notes on the iPhone. And using Dropbox is great – I can see the files on Dropbox, they’re not hidden away from me, i feel like i’m in control. I can back them up as I see fit, I can read them (kind-of), or really do anything I feel like. Plus, as of the v1.0+ Dropbox api, you get access to only tidy folder inside Dropbox/Apps to put the files for your app, which will put your users at ease. One last opinion: I think Dropbox is the best ‘cloud-y’ way to bridge the data divide between desktop (explorable file system) and mobile (no visible file system).

iCloud is a bit less awesome (to me) in this respect: the files are tucked away ‘in the cloud’ where you can’t see or touch them easily outside the app. I guess this is ideal for a consumer grade app, but for a power user this is a bit disconcerting. We all like to feel like we’re in control, which this approach (for me, at least) lacks. Plus it locks you to the Apple ecosystem AFAIK, and what if you wanted to make a PC version of your app?

My ideal syncing app

Here’s my ideal solution: the files to your app are all tucked away in a certain folder (eg: /Apps/MyApp) in Dropbox, and all the apps do a 2-way automatic sync between this and their local storage at startup/shutdown/change events. These files are all in some human readable format: YAML, JSON, or (shudder) XML. I personally prefer YAML because it is very human-readable for powerusers who like to open these files in a text editor. Also, because it is full of awesome (IMHO). However, i’ll understand if you prefer JSON or Plists or XML – that’s just my preference. In case you haven’t seen JSON, here’s how it looks:

id: 201327 name: Some Name hue: 300 icon: 248-sign some_array: – First – Second – Last

I’ve tried to follow this approach with my Service History app, and will use it in all my future apps where this kind of data sharing is appropriate. I also open-sourced the 2-way-syncing code, which is fairly simple and easy to integrate into your app, please check it out: CHDropboxSync.

One pitfall i’ve had with this solution was a user who contacted me, saying that when syncing one time the app deleted their data off their iPhone, rather than pushing it up to Dropbox. Now i can’t say for sure what happened in this situation, it’s impossible to know, but I think a nice solution would be that whenever the sync detects a remote delete, it should move the local file in a ‘Trash’ folder, and provide a UI for the user to restore files on a one-by-one basis if they want, just in case some bugs slipped through the radar. I’m planning on doing this with CHDropboxSync one day. Maybe for my current app-in-progress (a password syncer).

YAML

I’m a bit fan of YAML. I think it’s the only serialisation format that is optimised for readability. JSON is pretty close, but let’s be real here: it’s only readable to us devs, your average Joe is going to run away scared. YAML is so good, i’ll bet you could use it to serialise your monthly sales data, print it out verbatim, and give it to your CEO and he’d happily read it. Sometimes we devs need to get out of the ivory tower, I think. Use YAML, it’s friendly, people will love it.

One fair criticism is that it’s a bit difficult to find a good YAML library for ObjC. I recommend YAMLKit + libYaml. I tried YAML.framework, but it serialised in UTF16 which ruled it out for me. YAMLKit is a winner – it’s as simple as follows:

Read a yaml file into an NSDictionary:

NSDictionary *d = [YAMLKit loadFromFile:@“/Some/Path/To/My/File.yaml”];

Write an NSDictionary to disk in yaml format: [YAMLKit dumpObject:myDictionary toFile:@“/Some/Path/To/My/File.yaml”];

I’d really love a free YAML reader for mac to magically appear and make it’s way onto the app store, with a file association to the YAML file type. Imagine the feeling of ‘Oh sweet, I’m peeking behind the curtain, I can see my data, it’s readable and accessible’ when you user is poking through their Dropbox, finds the files to your app, double clicks one and it opens in textedit or a nice YAML visualisation tool. It’d be so empowering. I know I’d love it.

How to ping a server in Objective-C / iPhone

I recently had to make an iPhone app ping a server to check for it, and couldn’t find much helpful code out there. So I cobbled together a small helper which works with the SimplePing old code from apple’s site. Seems to work fine for me. Here’s how you’d use it:

- (void)tapPing {
    [SimplePingHelper ping:@"www.google.com"
        target:self sel:@selector(pingResult:)];
}

- (void)pingResult:(NSNumber*)success {
    if (success.boolValue) {
        [self log:@"SUCCESS"];
    } else {
        [self log:@"FAILURE"];
    }
}

Pretty simple to use – that’s all there is to it. The concept is that you use this as a very simple way of testing if networking will allow you to reach a server.

Keep in mind, that if you’re using this to poll a server to test for network connectivity, it’s probably worth using Reachability to check if they’re not connected to wifi, and if not then don’t ping too often for the sake of the poor old battery!

If it receives a response from the host, it calls pingResult immediately. If it doesn’t get a response, it times out after 1second and calls pingResult with failure.

It takes care of all the memory management for you, so you don’t have to worry about that. It retains target for 1 second, until it cleans up, so there’s no danger of it calling pingResult on a class that has been freed.

Source code can be found on github: https://github.com/chrishulbert/SimplePingHelper

To use it, grab the source and copy the 4 SimplePing* files into your project. Hope it helps someone!

iOS Automated Builds with Xcode4

iOS Automated Builds with Xcode4

I just spent the last (frustrating) week or more at work setting up our build server for some iPhone / iPad projects. It’s so complicated, and there’s so much misinformation out there, that it’s worth sharing some tips here which will hopefully be useful for us to read back on. And maybe this’ll save someone some hassles out there too.

In this article, i won’t give you a complete build script, as everyone’s environments are subtly different, but instead i hope to impart the knowledge and tips and pitfalls that’ll make it reasonably straightforwards for you to create your own script without all the horrible hassles I had.

Aims

Our final goal was to have two files arrive in our Dropbox each morning: zip files containing a dev branch build and a stage branch build. These zip files are to contain Xcode archives (for later app-store submission) and the ipa files (for TestFlight).

Our setup and requirements can be described thus:

  • A ruby script is used to control the build process.
  • Two Git branches: dev and stage. The idea is that all new features get added to the dev branch. Any bug fixes get added to the stage branch. Every two weeks (end of the sprint), with the testers' blessing, we merge all the new features from dev into stage, and then merge all the bug fixes from stage into dev.
  • We use TestFlight to provide the builds to the testers. For this, we need signed IPA files to submit to test flight.
  • We want to produce an Xcode archive (.xcarchive) – this is used for submission to the app store, and for sending to clients. With this file, we can double click it on any mac, which will import that exact build into Xcode, and we can then re-sign it with the App-store distribution profile and submit to the app store (so long as the Bundle Seed ID is the same – more on this later). This is so that we can ensure that what we submit to the app store is exactly the same build that was tested.
  • We’re using Xcode 4, and don’t need to support pre-iOS 4, so that simplifies things a lot (e.g. no need for CODE_SIGN_ENTITLEMENTS plists or Ad-hoc build configurations).

Provisioning

It’s worth going over provisioning: certificates, keys, profiles, etc. I’ll try to describe how it affects you, but you should really also read Technote 2250.

In short, it works like this:

Your private key signs a certificate, which validates provisioning profiles.

Keys and Certificates

Private keys are generated using the Keychain on your mac. Using this key, you request a certificate. So certificates only work if you have the matching private key installed – be aware of this, you cannot simply download the certificate from the iOS provisioning portal if you don’t have the private key. To copy a key to another computer, e.g. your build machine, right click > Export the key from within the Keychain, and make sure you export it as a .p12 file.

If, in the Keychain, you can’t see a little triangle next to your certificate, then it means your private key isn’t installed. Delete the certificate (it’s useless without the key), export the key from the original mac it was generated on, and import it on the other machine before you try importing the certificate.

You may see ‘Code sign identity’ mentioned in the project settings later on. This is a synonym for your certificate.

You’ll only need one distribution certificate, it’ll work for all your provisioning profiles (both adhoc and appstore).

Keep in mind that everything i’m discussing is to do with distribution, not development. Always ensure you’re in the ‘distribution’ tab in the iOS provisioning portal.)

Provisioning Profiles

You need two profiles: ad-hoc (TestFlight) and app-store.

When you generate a profile, it will be linked to your certificate, and will only work on a mac that has the cert (and key) installed. When you generate new profiles, however, you don’t need to re-generate the certificate – it isn’t necessary.

Profiles only work for a specific app id (discussed later), or they can work for a wildcard id. For this article, i’ll only be discussing those with specific app id’s.

When profiles are generated, they are locked to a Bundle Seed ID and a Bundle ID. When you compile an app, you must use a profile with a matching bundle id, or the profile won’t work. Your app’s bundle ID can be found in your Info.plist file.

Once an app has been signed with one profile (e.g. your ad-hoc TestFlight profile), you can re-sign it with another profile (e.g. your app-store profile) – IF the Bundle Seed ID’s match.

Provisioning profiles have a unique UUID to identify themselves, eg: 44A1166C-C096-4112-B3E0-9081520CBABC. This UUID can be extracted in the build script, as it changes each time you add a new device to your profile, and you don’t want to have to hunt down the UUID each time you re-generate the profile. It’s far easier to simply check the *..mobileprovision file into your repo, and let the build script look up the UDID, install the profile, and update the build settings accordingly.

App ID’s

An App ID = the Bundle Seed ID + ‘.’ + Bundle ID.

The Bundle Seed ID is also known as the App ID prefix, or the Team ID. When you generate a profile, it will be given your Team ID as it’s Bundle Seed ID. The Bundle Seed ID looks like: 5M3M5W7ABC.

Nowhere in your app’s configuration do you need to specify a bundle seed id, and the only time it matters is for app store submission time: when you want to submit the exact same build that the testers tested. When you go to re-sign the archive with your app store distribution profile, it’ll need to have the same Bundle Seed ID as in the ad-hoc profile you originally signed it with for testing.

The Bundle ID looks like: ‘com.splinter.myawesomeapp’. This is specified in your app’s Info.plist file. When you do a release/archive compile, you’ll need to sign against a provisioning profile that matches this bundle id. Eg, if you have two apps, with the following bundle id’s:

  • com.splinter.world-domination-app
  • com.splinter.servitude-app

In that case, you’ll need different profiles, with bundle id’s to match. (Or you can use wildcard profiles, but i won’t go into them here). The important thing to remember is: the bundle id in the profile must match your app’s bundle id, or it won’t compile.

Server setup

The server I use is a mac mini, with Bamboo. Personally, i don’t really recommend Bamboo as it over-complicates the git repository setup which makes it difficult to push commits up to your git server – which we use to make version number commits. You can use cron jobs, or Hudson, or any other CI setup you wish.

TestFlight

TestFlight has a brilliantly simply upload API that uses Curl from the command line to submit newer versions of your app. The only complication is if you wish to have both dev and stage branches available to your testers: since TestFlight groups builds by bundle name, only the most recent build will be available.

So, to get around this, I use ‘PlistBuddy’ to modify the app name and bundle ID prior to building the dev branch version. Please note that if you do this, you’ll also need to use a provisioning profile that matches the new bundle id.

Build Steps

The steps I follow for making a build are as follows:

  • Increment the version numbers in the Info.plist file
  • Check into git the updated Info.plist
  • Override the bundle id and name, if it is the dev branch
  • Install the provisioning profile
  • Use zerg_xcode to update the project file, to use the desired certificate and provisioning profile
  • Build the .xcarchive
  • Create the .ipa file
  • Upload to TestFlight

Incrementing versions

Our app’s versioning (for internal development and testing) follows a common major.minor.buildnumber strategy. Eg: 1.4.123. Each time the build runs, it increments the build number, updates the Info.plist, and checks it into git. The git commit uses the version number as the commit message so that later on we can see the exact code that was used to produce a given build.

To do this, PlistBuddy is used to extract the old version number, which is then incremented and saved to the Info.plist. In the ruby script, it looks like this:

oldVersion = `/usr/libexec/Plistbuddy -c "print :CFBundleVersion" Info.plist`.strip

This returns a string, such as ‘1.2.3’. We then need to increment this, which the following does:

components = oldVersion.split('.')
newBuild = components.pop.to_i + 1
components.push(newBuild).join('.')

We then need to save this new version number back to the Info.plist, which is a simple matter of using Plistbuddy again. So the complete function to read, increment, and save the file is as follows:

def incrementBundleVersion
    oldVersion = `/usr/libexec/Plistbuddy -c "print :CFBundleVersion" Info.plist`.strip
    components = oldVersion.split('.')
    newBuild = components.pop.to_i + 1
    version = components.push(newBuild).join('.')
    system("/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion #{version}\" Info.plist")
    system("/usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString #{version}\" Info.plist")
end

Don’t forget to add the code to check this back into Git after doing this.

Overriding bundle id and names

At this step, you can override the bundle id and bundle names. This is useful if you want to have different branches of your code available to your testers on TestFlight, such as dev and stage builds. Since TestFlight groups builds with the same bundle id/name, you’ll have to change it to do this.

PlistBuddy is used for this:

def overridePlistBundleName(infoPlist, name)
    system("/usr/libexec/PlistBuddy -c \"Set :CFBundleDisplayName #{name}\" \"#{infoPlist}\"")
    system("/usr/libexec/PlistBuddy -c \"Set :CFBundleName #{name}\" \"#{infoPlist}\"")
end

def overridePlistBundleId(infoPlist, id)
    system("/usr/libexec/PlistBuddy -c \"Set :CFBundleIdentifier #{id}\" \"#{infoPlist}\"")
end

Keep in mind of course that if you change the bundle id, you’ll need to use a different provisioning profile that matches the new bundle id.

Installing profiles

Your *.mobileprovision files should be checked into your repo, so that whenever you need to add a new device to your profile it is a simple enough job to update the profile on the iOS Provisioning Portal, download the updated profile, and check it in.

However, your profile will need to be installed. To do this, you first need to get the UUID out of the file, with code such as follows:

# Gets the uuid from a provisioning profile
def getProfileId(provisioningProfile)
    File.open(provisioningProfile,"r") {|f|
        raw = f.read
        nice = raw.gsub("\n","").gsub("\r","").
            gsub("\t","").gsub(" ","")
        matches = nice.scan(/UUID<\/key>(.*)<\/string>/)
        return matches.first.first
    }
    abort("Couldn't find UUID in: " + provisioningProfile)
end

Once you have the profile’s UUID, you can install it automatically, so that nobody has to log into the build server to install new profiles every time that someone updates the profiles. The code to install a profile:

# Installs a profile so we can compile against it and returns it's uuid
def installProfile(provisioningProfile)
    uuid = getProfileId(provisioningProfile)
    dest = File.expand_path("~/Library/MobileDevice/Provisioning Profiles/#{uuid}.mobileprovision")
    system("cp \"#{provisioningProfile}\" \"#{dest}\"")
    uuid
end

After installing the profile, you’ll need to store it’s UUID somewhere for later when it comes to updating the project file so that this profile is explicitly selected.

Zerg

Zerg_xcode is a ruby gem that is used to modify the Xcode project file so that we can explicitly set the provisioning profile and code signing identity (aka certificate).

It is unfortunate that we cannot set these as command line arguments and have to resort to updating the project files, but xcodebuild ignores build settings when archiving.

It is important to manually override the project file, as it gives us much more control over selecting the correct profile and certificate. This is necessary when we need to use different profiles for the different branches, because the bundle id’s are different for TestFlight’s sake (also, it prevents us from submitting a dev build to the app store!).

Here is the code I use to update the project file to manually set the certificate name (aka code sign identity) and profile’s UUID. Note that the certificate name is something like ‘iPhone Distribution: MY COMPANY’, which you can find in your keychain.

require 'rubygems'
require 'zerg_xcode' # https://github.com/ddribin/zerg_xcode

# Update the project to set the profile etc because
# xcodebuild only pays lip service to command line args
def doctorProject(target, identity, profileUuid)
    project = ZergXcode.load("MyProject.xcodeproj")

    configuration = 'Release'

    build_configurations = project["buildConfigurationList"]
        ["buildConfigurations"]
    configuration_object = build_configurations.select {|item|
        item['name'] == configuration }[0]
    configuration_object["buildSettings"]
        ["PROVISIONING_PROFILE"] = profileUuid
    configuration_object["buildSettings"]
        ["PROVISIONING_PROFILE[sdk=iphoneos*]"] = profileUuid
    configuration_object["buildSettings"]
        ["CODE_SIGN_IDENTITY"] = identity
    configuration_object["buildSettings"]
        ["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = identity

    target = project["targets"].select {|item|
        item['name'] == target }[0]
    build_configurations = target["buildConfigurationList"]
        ["buildConfigurations"]
    configuration_object = build_configurations.select {|item|
        item['name'] == configuration }[0]
    configuration_object["buildSettings"]
        ["PROVISIONING_PROFILE[sdk=iphoneos*]"] = profileUuid
    configuration_object["buildSettings"]
        ["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = identity

    project.save!
end

Build the .xcarchive

This is where the rubber hits the road: building the archive. Thankfully, with all the prerequisites taken care of by now, it’s a simple matter of the following:

xcodebuild -target "My Target" -scheme "My Scheme" -configuration Release clean archive

Note that we’re doing an ‘archive’, not a ‘build. It’s important to note the difference here. An archive builds a ’.xcarchive', whereas a build produces a .app and a .dsym. However, the .app and .dsym are fairly limited on their own – there’s not much you can do with them. An xcarchive is much more useful: you can import it into Xcode on another mac, re-sign it, and submit to the app store.

It is worth noting than an xcarchive is simply a package folder which contains the .app, .dsym, and a plist descriptor. So if you need the .dsym to symbolicate crashes later on, you can get it out of the xcarchive.

Xcodebuild will put the .xcarchive in a folder such as:

~/Library/Developer/Xcode/Archives/yyyy-mm-dd/MyArchive.xcarchive

To make it easier to find the just-generated archive, in my build script, before the xcodebuild step, I rename the Archives folder. Then after running the build, there will only be one xcarchive file inside the archives folder, which i grab, and then rename the Archives folder back as it was before building. This means that you can only run one build at a time on your build server, but it’s the best outcome given that you can’t control where the file is output.

The .xcarchive is really a folder, which contains the .app folder, among others. It contains symlink(s), which you have to be careful to preserve when copying, moving, and zipping it. If you break the symlink, you will get confusing code signing issues later on when you try to use it.

To preserve the symlinks, I make sure to use ‘mv’ to move the .xcarchive to my desired folder, as I could not get ‘cp’ to maintain relative symlinks. And when zipping it up, ensure that you use the -y option to preserve the symlinks, e.g.:

zip -rqy "MyOutput.zip" "/Folder/With/My/ArchiveAndIpa")
# -r means to recurse through folders, -q quiets the output,
# -y to preserve symlinks so as to not break codesigning

Create the .ipa file

Now that we have the .xcarchive, we need to produce the .ipa which we send to TestFlight for our testers to use. Use a utility called PackageApplication for this. But first you’ll need to find the path to the .app file within the .xcarchive first. I use the following in my ruby build script to do that:

app = Dir[outputFolder+'/*.xcarchive/Products/Applications/*.app'].first

And to generate the IPA filename that’ll go in my output folder:

ipa = outputFolder + '/' + File.basename(app).gsub('.app', '.ipa')

Once you have found those, perform something like the following:

/usr/bin/xcrun -sdk iphoneos PackageApplication
  "/Path/To/MyApp.app" -o "/Path/To/MyOutput.ipa"

One interesting point that took a while to realise, is that a lot of examples you’ll see on the internet for how to use PackageApplication are misleading: they show command line arguments for signing with a certificate and profile, but this is simply unnecessary, as your code was already signed as part of the archive process.

Also, be aware that PackageApplication only works if you pass it full, expanded paths for the .app and .ipa. So relative paths, or any path with ~ in it, will fail with no error message, confusingly. So be careful of that pitfall.

Upload to TestFlight

Once you have your ipa file, it is a simple matter of uploading it to TestFlight using their convenient curl api:

system("curl -F file=@\"#{ipa}\" -F api_token='#{token}'
  -F team_token='#{team}' -F notes=\"#{notes}\" -F notify=True
  -F distribution_lists='#{list}'
  \"http://testflightapp.com/api/builds.json\"")

This api is very simple and better documented on TestFlight’s site anyway, so i won’t get into it much here. It’s just worth reiterating that if you want dev and stage builds to be separately available on TestFlight for your testers, you’ll have to change the bundle id and bundle name as described in the section ‘Overriding bundle id and names’.

Xcode 4 - Command line builds of iPhone apps

Here’s the gist of how you can build your iPhone app from the command line. Change into the folder that contains your *.xcodeproj, and run the following:

xcodebuild -target "My Target" -scheme "My Scheme"
  -configuration Release clean archive

This will generate an xcode archive (*.xcarchive) in ~/Library/Developer/Xcode/Archives/DATE/… somewhere.

Now you’ve got your xcarchive, and assuming that your project was set up to sign using an ad-hoc provisioning profile, how to generate the IPA file that you can submit to TestFlight for your testers?

/usr/bin/xcrun -sdk iphoneos PackageApplication
  "/absolute/path/to/MyApp.xcarchive/Products/Applications/MyApp.app"
  -o "/absolute/path/to/MyApp.ipa"

Note that PackageApplication somehow only works if you use absolute paths. So ~ and relative paths don’t work – beware of that.

Now, if you’re clever, you can script all this with ruby to be nicely automated. I’ll get into that in another post. This is part one of a series on continuous integration of iOS apps that i’m working on…

Deep-enumerating a directory on the iphone, getting file attributes as you go

I found out the hard way, after lots of time wasted then a bit of googling, that NSFileManager’s enumeratorAtURL crashes! Don’t use it.

So if you need to recursively search a folder in objective-c (on the iPhone, in my case), grabbing all the attributes of the files (such as last-modified date), here’s an alternative way to do it. Please note this example uses ConciseKit:

NSMutableSet* pathsToSearch = $mset($.documentPath);
while (pathsToSearch.count) {
    // Pop a path to search
    NSString* pathToSearch = [pathsToSearch anyObject];
    [pathsToSearch removeObject:pathToSearch];

    // Scan it
    NSArray* contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pathToSearch error:nil];
    for (NSString* item in contents) {
        // Item is a file or a folder
        NSString* itemPath = [pathToSearch stringByAppendingPathComponent:item]; // Get the full path for it

        // Get the attributes
        NSDictionary* attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:itemPath error:nil];
        BOOL isDirectory = $eql([attribs $for:NSFileType], NSFileTypeDirectory);
        BOOL isFile = $eql([attribs $for:NSFileType], NSFileTypeRegular);
        NSDate* modified = [attribs $for:NSFileModificationDate];

        // Recurse if its a folder
        if (isDirectory) {
            [pathsToSearch addObject:itemPath];
        }

        // Do something with it
        NSLog(@"%@; %@", itemPath, modified);
    }
}

Memory management in Objective-C

This document is for one day in the future, if I find myself with a team of iOS devs and i need to get them to follow some ‘best practices’ when it comes to manual memory management, or hopefully some others out there in the world will find it useful.

Principles

  • Keep memory management code to a minimum
  • Avoid writing retain or release yourself
  • Use properties instead
  • Use autoreleased static constructors, eg: [NSArray array]
  • If you have to use alloc/init, autorelease on the same line
  • Use ARC for any new projects

Properties

Use properties for everything you need your Here’s how I suggest you declare properties, in your header:

@interface MyClass
@property(retain) NSMutableArray* myArrayProperty;
@end

Notice I don’t bother with ‘nonatomic’ properties. I don’t see any value in typing that unless you’ve got high-performance-critical code, in which case you should probably be re-thinking your algorithm or dropping down to C. Keep the typing to a minimum so we don’t all have RSI when we’re old.

And in your class, lay things out like this:

@implementation MyClass
@synthesize myArrayProperty;

- (void)dealloc {
    self.myArrayProperty = nil;
    [super dealloc];
}

Notice how the dealloc is directly underneath the synthesize declarations: this is so that whenever i create a property, i’m reminded to nil it out in the dealloc. Setting the properties to nil gets the synthesized setter to release any value if necessary. Important: if you don’t use the ‘self.’ then the synthesized setter won’t be used.

One thing worth noting, is that if you’ve got Key-Value Observers, they’ll be notified as you set these properties to nil and be passed a half-dealloced object, which will probably cause crashes. So if you’re using KVO, do the following instead: [myArrayProperty release]; myArrayProperty=nil;. Having said that, I’ve never found a need for KVO, and recommend against it for this issue. I personally prefer NSNotificationCentre.

If it’s a controller, I don’t really worry about how this exposes all my properties publicly. However, for business logic classes, it’s probably worth declaring the properties in a private category in the .M file instead of in the .H, so that they’re not externally accessible:

// Privates
@interface MyClass()
@property(retain) NSMutableDictionary* someProperty;
@end

@implementation MyClass
@synthesize someProperty;

- (void)dealloc {
    self.someProperty = nil;
    [super dealloc];
}

One more thing to keep in mind is that, for simplicity’s sakes, I exclusively use synthesized properties. I’ve simply seen too many bugs in hand-coded getters/setters.

Static constructors

Any static constructors, eg ‘NSArray array’ will return for you an autoreleased object. I always use these in preference to an [[[ABC alloc] init] autorelease], because generally they are cleaner and involve less typing. Plus you don’t have to think about when the value can be released, it’ll just get picked up by the autorelease pool after your function is done with it.

If you want to keep the value around for the duration of your class instance’s existence, do something like this:

self.myProperty = [NSArray arrayWithObjects:a, b, c, nil];

Alloc / init

As the saying goes: ‘if you init you own it’. Some classes don’t have static constructors, and you’ll have to resort to allocing/initing instances yourself. In these situations, I always recommend autoreleasing immediately after init'ing, that way i can treat them the same way as I do the static constructor instances. Also, if they’re on the same line, i don’t need to look down the code to see where it is autoreleased.

If you want to keep the value around for the duration of your class instance’s existence, do something like this:

self.myProperty = [[[Something alloc] init] autorelease];

IBOutlets

For any IBOutlet properties, I recommend usually using ‘assign’ properties, for these reasons:

  • You don’t need to worry about releasing them if the view gets unloaded and reloaded due to low memory
  • You won’t need to release them in your dealloc
  • The view will retain them for you so you won’t need to retain them

Although it has been pointed out to me that in the following cases, you may wish to make them ‘retain’ properties:

  • Some IBOutlets may not be views, and thus not retained by their superview
  • If you ever access an outlet property when the view is unloaded, you’ll have a dangling pointer crash

If you decide you need to make them retain properties, you’ll have to nil them out in both the dealloc and the viewDidUnload methods.

ARC

For new projects, ARC is definitely the way to go. Some libraries that you wish to include won’t be ARC-compatible yet, which is fine: you can disable ARC on a file-by-file basis for those.

To do this, open up your project node in the project navigator, select your target, go into the build phases tab, then expand the ‘Compile Sources’ section. Select all the files you need to disable ARC for, then press enter, and type -fno-objc-arc into the box that appears.

Summary

If you follow these principles, you should be able to keep your memory-management code to a minimum, and focus on the task at hand. If you ever see a ‘retain’ or ‘release’ anywhere, you’re probably making more work for yourself than you need to. Keep it simple!

Observer Pattern in Objective-C

Perhaps you’ve got a situation like this: A ‘middleware’ type class in your application, which let’s say for argument’s sake keeps track of sales on your website, through a timer or some sort of push mechanism. You’ve also got some other UI classes which would like to be notified whenever there’s fresh data in this middleware class, so they can update their display.

One early approach I pursued in achieving something like this was to use an array of listeners. The middleware class maintained an array of listeners, and other classes could add themselves to that array. Whenever there was new data, the middleware class would iterate through the array, calling some method with a name like ‘MiddlewareUpdated’.

Basically, this was a classic observer pattern.

But this method had a lot of issues:

Memory management

Since the middleware was a singleton, and it’s list of listeners retained the other UI classes, they would never get released. A couple of solutions to this were tried:

  • Making this list hold weak/assign references to the other classes. This involved a hacky non-retaining subclass of NSMutableSet. And if we forgot to remove the UI classes from the listeners upon their dealloc, crashy crashy!
  • Making the UI classes remove themselves from the listeners array on their viewDidDisappear. This meant that if they were a hidden tab, we couldn’t update them, and all sorts of tradeoffs.

Lots of code

This method meant lots of boilerplate, error-prone code to keep track of the listeners in the middle ware, adding and removing them and sending them update notifications. Also all the UI classes needed to implement the MyMiddlewareDelegate protocol. And so on.

Enough!

So here I propose a simpler solution: using NSNotificationCenter. This way you can implement the observer pattern or the publish-subscribe pattern with much less error-prone boilerplate code and simpler memory management issues.

This solution ‘goes with the grain’ more with iPhone development, as it uses the pre-existing mechanisms, so there’s less reinventing the wheel going on here.

So let’s see how this works in practice. Here’s an example of my middleware class:

..header file..
NSString* const MyMiddlewareHasUpdatedNotification;

..implementation file..
NSString* const MyMiddlewareHasUpdatedNotification =
    @"MyMiddlewareHasUpdatedNotification";

- (void)notifyObservers {
    [[NSNotificationCenter defaultCenter]
        postNotificationName:MyMiddlewareHasUpdatedNotification
        object:nil];
}

So whenever it wants to notify anyone that it has new data, it calls the [self notifyObservers] method.

Now in the UI classes that want to observe the middleware class for any updates, in their viewDidLoad or initWithNibName or initWithCoder functions, you subscribe to the notifications like so:

// Start observing the middleware for changes
- (void)observeMiddleware {
    [[NSNotificationCenter defaultCenter]
        addObserver:self
        selector:@selector(middlewareUpdated:)
        name:MyMiddlewareHasUpdatedNotification
        object:nil];
}

// When we're done, remove ourselves as an observer.
// That's it for memory management!
- (void)dealloc {
    [[NSNotificationCenter defaultCenter]
        removeObserver:self];
    [super dealloc];
}

// On startup, get the current state of the middleware
// and listen for future updates  
- (void)viewDidLoad {
    [self observeMiddleware];
    [self getInitialLoadFromMiddleware];
    [super viewDidLoad];
}

// Update the UI to reflect the latest data
- (void)getDataFromMiddleware {
    self.something = [[MyMiddleware instance] something];
    [self.tableView reloadData];
}

// Upon startup, get the initial data from the middleware class
- (void)getInitialLoadFromMiddleware {
    [self getDataFromMiddleware];
}

// This'll get called whenever the middleware has updated
- (void)middlewareUpdated:(NSNotification*)notification {
    [self getDataFromMiddleware];
}

The above example is slightly longer than necessary to illustrate how I prefer to grab the initial data and listen for later updates neatly. Really the only interesting parts are the observeMiddleware and middlewareUpdated methods.