Chris' Blog.

My occasional thoughts on iOS development, developers careers, trying to make an income from the App Store, and updates on life in general.

Project setup

In this post, I want to show you how I recommend configuring your Xcode project to satisfy the following common requirements:

  • Ability to point the app at either your Test API or Production API
  • Generate Test and Production API builds for TestFlight/HockeyApp
  • Generate builds for the App Store

Everyone has their own opinion on how these things should be set up, and there's a continuum from simple to complex that may be applicable for different situations, but at the least you may learn something here. And at best, you may copy my style verbatim. If I were to describe my setup, it is: As simple as possible, while still meeting the above requirements.

Oh, and if the images don't work in your RSS reader, be sure to open this post on my blog. And if they're too zoomed in, right click them and choose Open Image in New Tab (or whatever your browser's equivalent is).

Dimensions

It helps to think of the various dimensions that are involved here:

  • Test vs Production API
  • Debug vs Release (debug=simulator/running tethered to Xcode vs release=archives/app store/testflight)
  • Testflight vs App Store (only needed for release builds due to Xcode 6)

All the dimensions are unrelated to each other (orthogonal). Eg you will want a Test API build that runs in debug or release mode, and you'll want a Production API build that runs in debug or release mode. The exception is the app store build - there's no need a debug build for this one.

Xcode 6

Xcode 6 adds its own wrinkle to the picture. Previously, you could sign your Release build configuration archives with your App Store profile, and re-sign them with your Ad hoc profile for TestFlight/Hockey distribution (eg TestFlight's desktop app re-signs them for you).

But that no longer works, because Apple's added a new entitlement called 'beta-reports-active' to all the App Store profiles, for the purposes of the new 1000 Apple id's beta testing distribution. And when you re-sign a build that has that entitlement with an Ad hoc profile that is missing the entitlement, it won't install on your users devices. That's a bit of a recent gotcha to beware. So this is why I'm creating a separate profile and scheme specifically for the App Store build.

Build configurations

So now we can whittle it down to specifics. I recommend configuring your app to have the following build configurations:

  • Debug (you don't have to add this)
  • Debug Test API (duplicate of Debug)
  • Release (you don't have to add this)
  • Release Test API (duplicate of Release)
  • Release App Store (duplicate of Release)

If you forget how to add build configurations, open the project in Xcode's project navigator (the left pane), go to the project level, choose the Info tab, and click the '+' button underneath Configurations.

If you want to simplify further, you don't really need the App Store one - you can simply change Release's provisioning profile prior to each time you make an app store release, and then revert the change immediately using Git. But I personally keep the App Store config.

If you're using Cocoapods, keep in mind that whenever you add a build configuration you'll need to run pod install again so it'll automatically add the configurations to the pods project too.

It should look like this:

Configurations

User-defined build settings

I use user-defined build settings to drive the different bundle id and bundle display name for each version of the app. This gives us the ability to keep the test and production API versions of the app separate in Testflight, and makes it easier for testers to know which version they're using.

At the project level, select the 'Build Settings' tab, and select 'All' (not Basic), and 'Levels' (not Combined). We'll next need to add a couple user-defined settings that we can vary per build configuration. From the menu, choose Editor > Add Build Setting > Add User-Defined Setting to add each setting. Once you've added the two settings, click the triangle next to them to expand them, so you can add different values for each build configuration.

Here's the settings I recommend:

  • MY_BUNDLE_DISPLAY_NAME
    • Debug = MyApp
    • Debug Test API = MyApp Test
    • Release = MyApp
    • Release App Store = MyApp
    • Release Test API = MyApp Test
  • MY_BUNDLE_ID
    • Debug = com.mycompany.myapp
    • Debug Test API = com.mycompany.myapp.test
    • Release = com.mycompany.myapp
    • Release App Store = com.mycompany.myapp
    • Release Test API = com.mycompany.myapp.test

It should look like this:

User-defined settings

Of course, these user-defined settings on their own won't make a lick of difference to your bundle id/name, I'll get into applying them to your Info.plist in a few paragraphs.

Other build settings

You'll also need to set some further build settings for code signing and preprocessor macros.

Preprocessor Macros

Firstly, the simple ones: Navigate to the project-level settings, select the Build Settings tab, and search for 'Preprocessor Macros'. You simply need to change the two Test API ones to include TEST_API=1. Note that the 'Debug Test API' configuration should already have DEBUG=1 set, which you do not want to overwrite, you want to add TEST_API to that. Note that this macro has 'API' in the name, and is not simply 'TEST' - this is to emphasise the fact that this is intended to influence the API dimension only. These macros are used to make the app talk to your different backends, which I'll describe in a later paragraph. It should look like the following:

Preprocessor Macros

Code Signing

Next, you need to configure your code signing. Firstly, I recommend visiting ~/Library/MobileDevice/Provisioning Profiles, inspecting all your profiles using Provisioning Quick Look Generator, and deleting all the ones that you don't need. I even go so far as to put it in my Finder's sidebar and tidying this folder often. It really pays dividends when it comes to making sure Xcode signs your code predictably - I'm never left scratching my head wondering 'what did Xcode just do?' when it comes to code signing, which is where you should be as a professional. But I digress.

After removing the junk, you'll want to create two distribution provisioning profiles (unless you already have them) in the Apple Member Center - one for your Ad Hoc distribution (or an enterprise one if you're lucky), and one for App Store distribution. I recommend calling them 'MyCompany TestFlight' and 'MyCompany App Store'. Download them, then double-click to install them. You'll see them appear in the aforementioned library folder.

Once you've culled your installed provisioning profiles down to just what you need, then go into your target level build settings, and set the following:

  • Code Signing Identity
    • Debug / Debug Test API = Automatic iOS Developer
    • Release / Release Test API / Release App Store = iPhone Distribution: MyCompany
  • Provisioning Profile
    • Debug / Debug Test API = Automatic
    • Release / Release Test API = MyCompany TestFlight
    • Release App Store = MyCompany App Store

It should look like this:

Code Signing

Info.plist

You'll recall earlier that we created user defined build settings to vary the bundle id/name between build configurations. We need to change the Info.plist as follows so that these settings will be used:

  • Bundle identifier = ${MY_BUNDLE_ID}
  • Bundle name = ${MY_BUNDLE_DISPLAY_NAME}
  • Bundle display name = ${MY_BUNDLE_DISPLAY_NAME}

It should look like this:

Info plist

Code

In your code, wherever you make your API calls, you'll need some kind of constant to use as the base URL for API calls. You'll want to use #if to drive different base URLs for the test API, using the preprocessor macros you set earlier on the test api build configurations:

#if TEST_API
    static NSString *kBaseUrl = @"http://api-test.mycompany.com/v1/";
#else
    static NSString *kBaseUrl = @"https://api.mycompany.com/v1/";
#endif

Notice that the DEBUG macro has no bearing on whether you're pointing at the test API or not. We want to keep these dimensions orthogonal as mentioned earlier.

Schemes

You'll want to make a few schemes to make it easy to choose the build configurations. I make the following three:

  • MyApp Prod API
    • Run build configuration: Debug
    • Test build configuration: Debug
    • Profile build configuration: Release
    • Analyze build configuration: Debug
    • Archive build configuration: Release
  • MyApp Test API
    • Run build configuration: Debug Test API
    • Test build configuration: Debug Test API
    • Profile build configuration: Release Test API
    • Analyze build configuration: Debug Test API
    • Archive build configuration: Release Test API
  • MyApp App Store
    • Run build configuration: Debug
    • Test build configuration: Debug
    • Profile build configuration: Release
    • Analyze build configuration: Debug
    • Archive build configuration: Release App Store

When creating these three schemes, I make sure to check 'Shared' against them in the 'Manage Schemes' screen, so that they can be checked into Git.

Further thoughts

In the project settings, at target level, the General tab, under the Identity heading, there is a setting for Team. I set this to 'none' because I use my personal account for the tethered debugging provisioning profile. But you may want to use all your profiles from the same team, in which case you'll want to set this, as it drives the automatic code signing to be more specific.

Use a wildcard profile for the Ad hoc Testflight provisioning profile if you can get away with it, so you don't have separate ones for your .myapp and your .myapp.test bundle ids.

That's all for tonight, I hope this has been helpful!


Uploading to S3 from iOS

Sometimes it can be useful to upload files directly to an S3 bucket from an iOS app. Perhaps you're creating a video app and you need to upload videos to a staging area before your server can grab them. Or perhaps you're working on an app that is used for managing an S3 bucket's contents. Or perhaps you don't want to upload, but you want to use the AWS S3 API for other purposes, such as listing a bucket's contents.

In this article, I aim to explain how you can talk to the S3 API directly using Objective-C, for you to use in either an iOS or Mac app.

This is all based around the work I've done in S3Sync, a Mac console app for uploading to an S3 bucket. You can view it on github as a good example of how to do all this.

Request signing

The S3 api is a fairly typical RESTful api, but the main stumbling block is that each of your requests needs to be signed with an HMAC involving your amazon secret key. Luckily, there is the ever-helpful AFAmazonS3Client which can do the signing for us, when combined with AFNetworking.

Prerequisites

You'll need AFNetworking (version 2) and AFAmazonS3Client (also version 2) in your app. Cocoapods is probably your best bet for this, or you can download the appropriate tagged versions from their respective github repos and include the files directly, if you're not comfortable with the modifications that Cocoapods makes to your project files.

Setup

Firstly, you'll need to instantiate a manager object to use for later requests. You can do this as follows:

AFAmazonS3Manager *s3Manager =
    [[AFAmazonS3Manager alloc] initWithAccessKeyID:@"MYAMAZONKEYID"
                                            secret:@"MYAMAZONSECRET"];
s3Manager.requestSerializer.region = AFAmazonS3USStandardRegion;
s3Manager.requestSerializer.bucket = @"MYBUCKETNAME";

You don't need to set the region, but perhaps by setting it you can make things faster if you're eg using a Sydney bucket.

If your bucket is being used to host a website, it will be something like "www.splinter.com.au".

Note that you'll probably want to obfuscate the key id and secret in your app, I wrote about this here: Storing Secret Keys.

Getting a list of files from a bucket

To get a list of files (objects, in S3-terminology), you can use the following:

/// Marker is nil for when you call this, it is only used for recursive calls.
- (void)getS3ListFromMarker:(NSString *)marker {
    NSDictionary *params = marker ? @{@"marker": marker} : nil;

    [s3Manager GET:@"/" parameters:params
        success:^(AFHTTPRequestOperation *operation, NSXMLParser *responseObject) {

        // Parse the response.
        ListObjects *myParsedObject = ...

        // TODO keep track of the files listed so far, add them to previous.

        // Fetch more files if necessary.
        if (myParsedObject.isTruncated) {
            S3Object *lastObject = myParsedObject.objects.lastObject;
            [self getS3ListFromMarker:lastObject.key];
        } else {
            // TODO finished!
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error: %@", error);
    }];
}

I haven't described how you'll parse the response, it's formatted in XML (not JSON, surprisingly!) which is a bit trickier. But it's fairly straightforwards, and is left as an exercise for the reader (or you could look at S3Sync, link is above). The two main things you need to parse are the list of objects, and the 'IsTruncated' field.

The main thing to note here is that the response only returns up to 1000 files at a time. If there are more than that many files, IsTruncated will be true and you'll need to recursively request again, with the 'marker' parameter set to the key of the last object returned in the previous call.

Uploading a file

To upload a file, you'll firstly need the mime type. If you don't already know it, a clever way to guess the mime type is to use NSURLConnection with a file url, as below:

// Get the file using url loading mechanisms to get the mime type.
NSMutableURLRequest *fileRequest = [NSMutableURLRequest requestWithURL:
    [NSURL fileURLWithPath:myLocalFileFullPath]];
fileRequest.cachePolicy = NSURLCacheStorageNotAllowed;
NSURLResponse *fileResponse = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:fileRequest
                                     returningResponse:&fileResponse 
                                                 error:nil];
// Mime type is now in fileResponse.MIMEType.

It's also highly recommended to get the MD5 of the file, and Base-64 encode it, to ensure nothing gets corrupted while uploading. You'll need to #import <CommonCrypto/CommonCrypto.h> too:

unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
CC_MD5(data.bytes, (CC_LONG)data.length, md5Buffer);
NSData *md5data = [NSData dataWithBytes:md5Buffer length:sizeof(md5Buffer)];
NSString *md5Base64 = [md5data base64EncodedStringWithOptions:0];

Next, you need to generate the request. Since we'll be mutating parameters in the url request, we won't be able to use AFNetworking's handy single-shot GET or PUT methods, instead we'll need to form requests as below:

// Build the un-authed request.
NSURL *url = [s3Manager.baseURL URLByAppendingPathComponent:
    @"somefolder/subfolder/video_to_upload.mp4"];
NSMutableURLRequest *originalRequest = [[NSMutableURLRequest alloc] initWithURL:url];
originalRequest.HTTPMethod = @"PUT";
originalRequest.HTTPBody = data;
[originalRequest setValue:md5Base64 forHTTPHeaderField:@"Content-MD5"];
[originalRequest setValue:fileResponse.MIMEType forHTTPHeaderField:@"Content-Type"];

Note the path component above is the remote path to upload to on the bucket.

Once we've created the request, it needs to be 'signed' using your secret key. Basically it sets an HTTP header field. This is where AFAmazonS3Client does its magic:

// Sign it.
NSURLRequest *request = [s3Manager.requestSerializer
    requestBySettingAuthorizationHeadersForRequest:originalRequest 
                                             error:nil];

And once that is all done, you can create the AFNetworking request operation and add it to the queue, which starts it:

// Upload it.
AFHTTPRequestOperation *operation = [s3Manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
    // Success!
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error uploading %@", error);
}];
[s3Manager.operationQueue addOperation:operation];

If you want the code in one chunk, rather than split up and explained here, please check out S3Sync (linked above).

Also, if you want to upload a file > 5MB, you can use S3's Multipart upload, but I have not covered that here.

That's all for today, I hope this has been helpful.


iOS8 App Testing Roundup

Now that iOS8 is out, we've got another option for distributing development versions of our app to beta testers. So I thought it'd be useful to do a roundup of all your options, with their pros and cons.

Ad-hoc signing

This is the tried-and-true option where you gather your testers' UDID's, input their UDID's into the iOS Dev Center, and generate an Ad Hoc Distribution profile. It is a bit tricky nowadays to get access to a phone's UDID, so people often use TestFlight or HockeyApp to install a profile on the tester's phone in order to gather their UDID's. Alternatively, you can connect a phone to a computer and use Xcode's organizer to grab the UDID.

  • Limits you to 100 testers.
  • You need to get testers' UDIDs. When bringing on new testers, you need to re-generate your provisioning profile.
  • I recommended this for indie developers only.

Enterprise accounts

This is the holy grail for testing: No mucking around with UDIDs is required. It just costs a little more per year, but this is highly recommended for any enterprise situations.

  • Unlimited testers, so long as you abide by the terms of Apple's agreement.
  • To get an enterprise account, you'll need to apply to get a DUNS number from Dun and Bradstreet.
  • Costs a little more (~$300/year as opposed to ~$100/year) to get an account.
  • I recommend this if you work in a big company. And if so, start chasing up the DUNS in the early stages of your project, before you need it!

Jailbreak

This is always an option! Most people don't do this, but I guess it certainly is one way of getting around all this code signing guff.

  • Possibly worth testing if you're targeting markets (eg China) where most phones are jailbroken, just to make sure your app works fine on a jailbroken phone.
  • I recommend... not really doing this.

iOS8 TestFlight

This is the new option available to us. However, it is not without its cons. This allows you to distribute your app to up to 1000 testers (so, unlimited for most intents and purposes). The catch is that your app has to undergo the scrutiny of App Store reviewers before going out to your testers. Eg a 10-day delay, at the current review rate. That's a pretty big catch! So this is not useful for day-to-day testing, this is more for distribution to the press just prior to going live.

  • Limited to 1000 Apple id's.
  • No limit on devices (eg John Doe who owns an iPad, iPhone, and iPod counts as one tester).
  • Apps need to be reviewed by Apple, which means 1 or 2 weeks delay.
  • Possible to avoid the review process for minor updates. I'm not sure what the definition of 'minor' is.
  • I've read that it's possible to avoid the review process for this, if the testers are admins on your apple account. But that doesn't sound very secure.
  • I recommend this for sending your almost-finished versions of the app to the press / reviewers / distributors.

Hope that helps!


You can see older posts in the right panel, under 'archive'.

Archive

Project setup in Xcode6 22 Oct 2014

Uploading to an S3 bucket from iOS 15 Oct 2014

iOS8 App Testing Roundup 28 Sep 2014

Storing obfuscated secret keys in your iOS app 16 Sep 2014

Getting Core Location / CLLocationManager to work on iOS8 14 Sep 2014

Accessing the response body in failure blocks with AFNetworking 2 10 Sep 2014

How to allow your UITextFields to scroll out of the way of the keyboard 8 Sep 2014

How to subclass UIButton in iOS7 and make a UIButtonTypeSystem 4 Sep 2014

New season 1 Aug 2014

House finished 17 Jun 2014

WebP decoding on iOS 9 Feb 2014

Moving on again 22 Jan 2014

Lossy images for retina iPads - JPEG vs WebP 30 Nov 2013

Career options I wish I knew about when I was younger 20 Oct 2013

Positivity and your friends 7 Oct 2013

Tactility 26 Jul 2013

WWDC-induced narcolepsy 15 Jul 2013

Back on rails 31 May 2013

Full circle 6 May 2013

Programmatic UI on iOS 3 May 2013

Screencasts and positivity 8 Apr 2013

Year of positivity 14 Mar 2013

iOS Dev State of the Union 6 Feb 2013

Adventures with IAPs 3 Feb 2013

No longer a Googler 23 Dec 2012

Localising iPhone apps with Microsoft Translator 8 Dec 2012

Fight back (app biz update 13) 12 Nov 2012

Sent to the backburner (app biz update 12) 25 Oct 2012

Lisi Schappi 7 Oct 2012

Today's happy plateau (app biz update 11) 26 Aug 2012

First week's sales of Today (app biz update 10) 19 Aug 2012

Today launch! And a difficult decision made... (app biz update 9) 15 Aug 2012

Approved! (app biz update 8) 5 Aug 2012

Creating a graph in Objective-C on the iPhone 3 Aug 2012

Hurry up and wait (app biz update 7) 30 Jul 2012

Today app marketing site 27 Jul 2012

Today app submitted 25 Jul 2012

UIAlertView input wrapper 24 Jul 2012

Mentoring 23 Jul 2012

This is too hard! (app biz update 6) 20 Jul 2012

Perspectives (app biz update 5) 9 Jul 2012

4th starting-my-own-biz update 1 Jul 2012

ScrumFox landing page 28 Jun 2012

Server Scope landing page 27 Jun 2012

Telstra Calls and Data Usage 26 Jun 2012

Service History + Dropbox 26 Jun 2012

Impromptu Presenter 26 Jun 2012

Fertility Tracker 26 Jun 2012

Baby Allergy Tracker 26 Jun 2012

Starting my own business, update 3 22 Jun 2012

Starting my own business, update 2 17 Jun 2012

Starting my own business - First update 10 Jun 2012

I must be crazy 6 Jun 2012

Finding your location on an iPhone 7 May 2012

A generous career 4 May 2012

Skeleton Key Cocoaheads presentation 3 May 2012

CHBgDropboxSync - Dropbox auto-sync for your iOS apps 1 May 2012

That book about that Steve Jobs guy 30 Apr 2012

Another app marketing idea 23 Apr 2012

Sweet grouped tables on the iPhone 17 Apr 2012

Skeleton Key App 11 Apr 2012

Another app marketing idea... 5 Apr 2012

Quickly check for any missing retina graphics in your project 3 Apr 2012

Skeleton Key Password Manager with Dropbox 2 Apr 2012

RC Boat motor finally mounted 2 Apr 2012

Promoting apps presentation slides 1 Apr 2012

How i just wasted a month on my latest app, and how you don't need to 26 Mar 2012

The Finishing Line 20 Mar 2012

Using Launchd to run a script every 5 mins on a Mac 20 Feb 2012

Generating AES256 keys from a password/passphrase in ObjC 20 Feb 2012

Indie iPhone app marketing, part 2 19 Feb 2012

My App Manifesto: Syncing + Dropbox + YAML = Awesome 15 Feb 2012

Indie iPhone App Marketing part 1 7 Feb 2012

Perspectives 2 Feb 2012

Accountability and Free Will 1 Feb 2012

Badassery 31 Jan 2012

Sacrifice 30 Jan 2012

Lead Yourself First 29 Jan 2012

How to ping a server in Objective-C / iPhone 26 Jan 2012

iOS Automated Builds with Xcode4 16 Jan 2012

Xcode 4 - Command line builds of iPhone apps 15 Jan 2012

Guest post by Jason McDougall 13 Jan 2012

Scouts, Games and Motivation 10 Jan 2012

2011 Re-cap 8 Jan 2012

Ruby script to increment a build number 4 Jan 2012

Turning 30? All ideas, no execution? 18 Dec 2011

CHDropboxSync - simply sync your iOS app's documents to Dropbox 14 Dec 2011

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

Getting a date without the time component in objective-c 6 Dec 2011

Memory management in Objective-C 4 Dec 2011

Starting small 29 Nov 2011

Dictionary Types Helper 29 Nov 2011

Observer Pattern in Objective-C 16 Nov 2011

Why you should give presentations 13 Nov 2011

How to get a programming or design job in Sydney 9 Nov 2011

Custom nav bar / toolbar backgrounds in iOS5 8 Nov 2011

Stuck 27 Oct 2011

Dead easy singletons in Obj-C 19 Oct 2011

JSON vs OCON (Objective-C Object Notation) 18 Oct 2011

In defence of Objective-C 16 Oct 2011

Update the MessagePack objective-c library to support packing 12 Oct 2011

Icons 11 Oct 2011

How to host a site on Amazon AWS S3, step-by-step 7 Oct 2011

Drawing a textured pattern over the default UINavigationBar 6 Oct 2011

Markdown Presentations 1 Oct 2011

More MegaComet testing: Ruling out keepalives 15 Sep 2011

MegaComet test #4 - This time with more kernel 14 Sep 2011

Building People 10 Sep 2011

Half way there: Getting MegaComet to 523,000 concurrent HTTP connections 5 Sep 2011

Making a progress bar in your iPhone UINavigationBar 22 Aug 2011

Hacker News Reader 20 Aug 2011

How to programmatically resize elements for landscape vs portrait in your iphone interface 16 Aug 2011

MegaComet testing part 2 3 Aug 2011

Australian Baby Colours 28 Jul 2011

Boat prop shaft 25 Jul 2011

Megacomet with 1 million queued messages 24 Jul 2011

Installed the strut and rudder 18 Jul 2011

Painted the inside of the boat 17 Jul 2011

Fuzzy iphone graphics when using an UIImageView set to UIViewContentModeCenter 13 Jul 2011

My 3 Data and Calls Usage 11 Jul 2011

Reading a line from the console in node.js 10 Jul 2011

Trim whitespaces on all text fields in a view controller 9 Jul 2011

Final finish 9 Jul 2011

MessagePack parser for Objective-C / iPhone 30 Jun 2011

Lacquering the starboard side 25 Jun 2011

What do do with EXC_ARM_DA_ALIGN on an iPhone app 23 Jun 2011

Lacquering the hull 23 Jun 2011

Staining the boat 22 Jun 2011

NSMutableSet with weak references in objective-c 20 Jun 2011

Iphone gesture recogniser that works for baby games 20 Jun 2011

Image manipulation pixel by pixel in objective C for the iphone 19 Jun 2011

Baby Allergy Tracker 12 Jun 2011

Power sanding the deck 10 Jun 2011

Planing the edge of the deck 2 Jun 2011

Figured out the deck 2 Jun 2011

Boat bulkheads 2 Jun 2011

Simulating iOS memory warnings 31 May 2011

Putting a UIButton in a UIToolbar 29 May 2011

How to allow closing a UIActionSheet by tapping outside it 29 May 2011

Finding the currently visible view in a UITabBarController 24 May 2011

Random Chef 17 May 2011

Centered UIButton in a navigation bar on the iphone 16 May 2011

Little Orchard 13 May 2011

Boat update 13 May 2011

How to get the current time in all time zones for the iphone / obj-c 12 May 2011

Design portfolio 10 May 2011

Tricks with grand central dispatch, such as objective-c's equivalent to setTimeout 9 May 2011

How to make an iphone view controller detect left or right swipes 5 May 2011

Centered section headers on a UITableView 5 May 2011

Christmas in may 4 May 2011

Finished trimming the boat (its floatable now!) and got some parts 29 Apr 2011

How to make a multiline label with dynamic text on the iphone and get the correct height 27 Apr 2011

Forcing an image size on the image in a table view cell on an iphone 20 Apr 2011

Git on the Mac 19 Apr 2011

Build a url query string in obj-c from a dictionary of params like jquery does 12 Apr 2011

Rendering a radial gradient on the iphone / objective-c 11 Apr 2011

Skinning the port side of the boat 8 Apr 2011

Skinning the side of the boat 5 Apr 2011

Sending a UDP broadcast packet in C / Objective-C 5 Apr 2011

How to talk to a unix socket / named pipe with python 4 Apr 2011

Skinning the bottom of the boat 31 Mar 2011

Service discovery using node.js and ssdp / universal plug n play 30 Mar 2011

Extremely simple python threading 29 Mar 2011

New rescue boat 26 Mar 2011

HttpContext vs HttpContextBase vs HttpContextWrapper 5 Nov 2010

Simple C# Wiki engine 30 Sep 2010

Simple way to throttle parts of your Asp.Net web app 29 Sep 2010

How to implement DES and Triple DES from scratch 4 Aug 2010

How to use sessions with Struts 2 30 Jul 2010

How to use Cookies in Struts 2 with ServletRequest and ServletResponse 30 Jul 2010

Using Quartz Scheduler in a Java web app (servlet) 27 Jul 2010

Javascript date picker that Doesn't Suck!(tm) 27 Jul 2010

Using Oracle XE with Hibernate 20 Jul 2010

A simple implementation of AES in Ruby from scratch 29 Jun 2010

Asp.Net Forms authentication to your own database 28 May 2010

AS2805 (like ISO8583) financial message parser in C# 7 May 2010

Ruby hex dumper 4 May 2010

Using Spring to manage Hibernate sessions in Struts2 (and other web frameworks) 13 Jan 2010

Emails in C#: Delivery and Read receipts / Attachments 12 Jan 2010

Using Java libraries in a C# app with IKVM 16 Dec 2009

Learning Java tutorial 27 Nov 2009

Using generic database providers with C# 17 Nov 2009

Scheduled task executable batch babysitter 29 Oct 2009

Working with query strings in Javascript using Prototype 30 Sep 2009

Still fighting with String.Format? 9 Sep 2009

How I'd build the next Google 24 Aug 2009

Getting IIS and Tomcat to play nicely with isapi_redirect 24 Aug 2009

Using the new ODP.Net to access Oracle from C# with simple deployment 11 Aug 2009

C# Cryptography - Encrypting a bunch of bytes 14 Jul 2009

Sorting enormous files using a C# external merge sort 10 Jul 2009

Reconciling/comparing huge data sets with C# 9 Jul 2009

Some keyboard-friendly DHTML tricks 10 Jun 2009

How to figure out what/who is connected to your SQL server 18 Mar 2009

Adding a column to a massive Sql server table 16 Mar 2009

Multithreading using Delegates in C# 10 Mar 2009

Using C# locks and threads to rip through a to-do list 6 Feb 2009

Using threads and lock in C# 3 Feb 2009

Setting a form name and onsubmit using form_for in rails 2 14 Jan 2009

Compressing using the 7Zip LZMA algorithm in C# beats GZipStream 14 Jan 2009

Bare minimum HTML that validates 22 Dec 2008

MS Sql Server 2005 locking 17 Dec 2008

Simple Comet demo for Ruby on Rails 19 Nov 2008

Geocoding part 2 - Plotting postcodes onto a map of Australia with C# 24 Oct 2008

Using evolutionary algorithms to make a walkthrough for the light-bot game with C# 20 Oct 2008

How to tell when memory leaks are about to kill your Asp.Net application 16 Oct 2008

C# version of isxdigit - is a character a hex digit? 15 Sep 2008

Geocoding part 1 - Getting the longitude and latitude of all australian postcodes from google maps 26 Aug 2008

Converting HSV to RGB colour using C# 14 Aug 2008

Opening a TCP connection in C# with a custom timeout 11 Aug 2008

Oracle Explorer - a very simple C# open source Toad alternative 31 Jul 2008

Linking DigitalMars' D with a C library (Mongrel's HTTP parser) 23 Jun 2008

Connecting to Oracle from C# / Winforms / Asp.net without tnsnames.ora 16 Jun 2008

A simple server: DigitalMars' D + Libev 6 Jun 2008

Travelling from Rails 1 to Rails 2 9 Apr 2008

Rocketsale 9 Apr 2008

Online Rostering System 9 Apr 2008

DanceInforma 9 Apr 2008

Client Analyser 9 Apr 2008

How good is this??? 16 Dec 2007

Using RSS or Atom to keep an eye on your company's heartbeat 10 Nov 2007

Easy Integrated Active Directory Security in ASP.Net 24 Oct 2007

First post 17 Oct 2007