tapsquare

We create software for iOS and Mac OS X.
Need Some? Get In Touch

October 14, 2010 at 8:20am

Craig Hockenberry on iOS development costs →

Craig Hockenberry of Twitteriffic fame lays out the development costs for Twitteriffic for iPad in some detail.

July 12, 2010 at 1:27pm

iPod Library Access

So you want your app to somehow process raw PCM samples from the user’s iPod Library in iOS4. Maybe you need to timestretch those tracks for a DJ app, or maybe you want to write a visualizer. Or maybe you want to write an app that makes it sound like your user’s entire music library was performed by Darth Vader.

In versions of iOS prior to 4.0, you couldn’t get access to those bits. You could use the MediaPlayer framework to browse and play files from the user’s iPod Library, but you couldn’t actually process those files.

I’m happy to report that thanks to additions to the AVFoundation and MediaPlayer frameworks in iOS 4.0, you can create local copies of iPod Library files for your app to open. Basically, you use a new property on MPMediaItemMPMediaItemPropertyAssetURL—to get a special URL that can only be used with AVFoundation apis. You then use this URL to create an AVAssetExportSession and ‘export’ the file to somewhere in your app’s local directory structure.

What’s somewhat tricky is choosing values for the preset and outputFileType properties of AVAssetExportSession. Without the exact right combination of input file type, preset and outputFileType, you’ll get cryptic errors, zero-length output files, or ridiculously long transcoding times.

Enter TSLibraryImport, a simple, MIT-licensed open-source class that makes it trivial (one method call) to get iPod Library files copied into your app for further processing. You can grab the source over at the project’s bitbucket

I hope you find it useful, and if you make something cool with it, please let me know!

UPDATE 7/14/10: If you have an iPhone Developer Account, you may want to have a look at today’s 4.1 SDK beta before using TSLibraryImport.

UPDATE 7/19/10: Chris Adamson has an excellent write-up on getting files out of the iPod Library over at Time Code Our methods are similar—he transcodes files to m4a/aac on import while TSLibraryImport uses passthrough—but his explanation of how this all works vis-á-vis AVAssetExportSession is lucid, detailed and well-written.

July 2, 2010 at 9:11am

WWDC 2010 Source Code →

Just found out that even those who didn’t attend can download the source code from WWDC 2010 at this link. Great for following along with the session videos.

June 30, 2010 at 1:01pm

Cleaning up with Blocks

Here’s something I encounter writing C code every day: In a function, you allocate some resource and then perform some initialization on the resource. If any of these initializations fail, you need to clean up the resource, which can lead to considerable repetition and opportunities for leaks. Consider the following code.

[...]

AudioComponent comp = AudioComponentFindNext(NULL, &desc);

AudioUnit audioUnit;

// Create a new instance of the RemoteIO Audio Unit
err = AudioComponentInstanceNew(comp, &audioUnit);
if (noErr != err) return err;

// enable input
UInt32 one = 1;
err = AudioUnitSetProperty(audioUnit, 
                           kAudioOutputUnitProperty_EnableIO, 
                           kAudioUnitScope_Input, 
                           1, &one, sizeof(one));
if (noErr != err) { AudioComponentInstanceDispose(audioUnit); audioUnit = NULL; return err; }

// Setup our callback
AURenderCallbackStruct renderCallback;
renderCallback.inputProc = TSInputProc;
renderCallback.inputProcRefCon = NULL;

err = AudioUnitSetProperty(audioUnit,
                           kAudioUnitProperty_SetRenderCallback,
                           kAudioUnitScope_Input,
                           0,
                           &renderCallback,
                           sizeof(renderCallback));
if (noErr != err) { AudioComponentInstanceDispose(audioUnit); audioUnit = NULL; return err; }

[...]

And so on. Note that with every error check we have some copy/paste cleanup code: AudioComponentInstanceDispose(audioUnit); audioUnit = NULL; This clearly violates DRY and can lead to leaks as your code grows and you forget to copy clean-up code to all the possible function termination points.

One way I’ve seen this handled is with a goto statement:

err = AudioUnitSetProperty(audioUnit,
                           kAudioUnitProperty_SetRenderCallback,
                           kAudioUnitScope_Input,
                           0,
                           &renderCallback,
                           sizeof(renderCallback));
if (noErr != err) goto BAIL;

[...]
    // forget this return (who hasn't?) and execution falls through to
    // your BAIL: handler. Hilarity ensues as your function returns noErr
    // but all your resources are released.
    return noErr; 

BAIL: 
    if (NULL != audioUnit) { AudioUnitComponentInstanceDispose(audioUnit); audioUnit = NULL; }
    if (IsInstantiated(someOpaqueType)) { Dispose(someOpaqueType); }
    return err;

Yeah. goto is the poor man’s exception. This works well enough, but can get somewhat complicated, as it requires that you test that each resource was actually instantiated since BAIL: can be reached from anywhere in your function. This is straightforward for pointer types—just check for NULL—but requires function calls for certain opaque types, file handles, etc.

I’ve always hated the goto method, so I’m trying something new: Blocks. Using blocks when doing iOS or Mac OS X development lets you declare cleanup once at the resource’s initialization site and lets you compound cleanup operations for additional resources as they’re successfully allocated.

[...]

AudioComponent comp = AudioComponentFindNext(NULL, &desc);

// __block lets a block modify a local from its enclosing lexical scope
__block AudioUnit audioUnit;

err = AudioComponentInstanceNew(comp, &audioUnit);

// block for error cleanup
void (^errorCleanup)() = ^() {
    AudioComponentInstanceDispose(audioUnit);
    audioUnit = NULL;
};

if (noErr != err) return err;

// enable input
UInt32 one = 1;
err = AudioUnitSetProperty(audioUnit, 
                           kAudioOutputUnitProperty_EnableIO, 
                           kAudioUnitScope_Input, 
                           1, &one, sizeof(one));
if (noErr != err) { errorCleanup(); return err; }

// Setup our callback
AURenderCallbackStruct renderCallback;
renderCallback.inputProc = TSInputProc;
renderCallback.inputProcRefCon = NULL;

err = AudioUnitSetProperty(audioUnit,
                           kAudioUnitProperty_SetRenderCallback,
                           kAudioUnitScope_Input,
                           0,
                           &renderCallback,
                           sizeof(renderCallback));
if (noErr != err) { errorCleanup(); return err; }

// allocate another resource

__block SomeOpaqueType opaqueType;

err = SomeOpaqueTypeCreate(&opaqueType);
if (noErr != err) { errorCleanup(); return err; }

// define new error cleanup function 
void (^oldCleanup)() = errorCleanup;
errorCleanup = ^() {
    // clean up this resource
    SomeOpaqueTypeDispose(&opaqueType);
    // perform any earlier cleanup
    oldCleanup();
}

err = SomeOpaqueTypeDoSomething(opaqueType, someValue);
if (noErr != err) { errorCleanup(); return err; }


[...]

// malloc some data
__block float* buffer = (float*)malloc(bufferSize*sizeof(float));
if (NULL == buffer) errorCleanup(); return OUT_OF_MEMORY_ERR;

oldCleanup = errorCleanup;
errorCleanup = ^() {
    free(buffer);
    buffer = NULL;
    oldCleanup();
}

err = SomeOperationThatMightFail(buffer);
if (noErr != err) { errorCleanup(); return err; }

[...]

This provides several benefits over the goto method:

  • Cleanup for each resource allocation is defined once, immediately after the resource is allocated.
  • Cleanup operations are composed. Essentially we’ve created a stack of anonymous cleanup functions. Whenever you test for an error, on failure you only need call one function, errorCleanup, and you know you won’t leak any resources that have been allocated up to that point.
  • All the cool computer scientists love closures.

There is at least one significant drawback to this approach: Blocks aren’t portable, so if you need code that can compile on a system other than iOS4 or Mac OS X 10.6, this won’t work for you.

I’m curious how other programmers handle resource cleanup (and error handling in general) in plain old C. Hit me up in the comments.

June 28, 2010 at 10:03am

By the numbers.

In a press release today, Apple announced they sold over 1.7 million iPhone 4 units in the first 72 hours after launch.

I wrote a blog post a while back about getting your head around these kind of numbers.

There are 259,200 seconds in 72 hours.

That means Apple put an iPhone 4 in someone’s hand on average every 150 milliseconds for 72 hours straight. That’s six-and-a-half units per second.

That’s a lot of phones.

9:32am

reblogged from marco

Marco.org: Rambling about Verizon →

Even an optimistic and probably unrealistic estimate of 2013 is far too long of a wait. Apple’s quickly losing ground to Android today for only one reason: the majority of mobile-phone owners in the U.S. (the majority of people in the U.S.) choose their network first and their phone second. The phone selection is nearly an afterthought. They go to the nearest red phone store when their two-year contracts expire and pick out their next phone from whatever they see in the store.

June 18, 2010 at 9:18am

We might also do well to note how closed mobile development was before the iPhone. I know I’ve told this story before, but in a JavaOne conversation with O’Reilly people about how to get Java ME books moving, I said that everyone with an interest in ME (myself included) had figured out that getting your apps to end users was effectively impossible, and that with the network API often disabled for third-party apps, there wasn’t much point in writing ME apps anyways. My suggestion for an ME book that would move copies would be one which provided “the names, e-mails, and phone numbers of all the carrier and handset executives you’d have to go down on in order to get your apps on their phones.”

— Wii are selective in our outrage

June 17, 2010 at 12:01pm

WWDC 2010 videos available free to all registered developers! →

Wow. In years past, these session videos and slides were only free for attendees—developers who didn’t make it had to pony up a sizable chunk of change.