In “episode 21 of Core Intuition”:www.coreint.org/2009/07/e… I called the Image Capture API “quirky”. What did I mean by that? A few things.
Refcon. This should be familiar to anyone who has built Mac OS 9 or Carbon apps. I’ve certainly written plenty of code that stuffed a pointer to an object in the refcon field of a structure or passed to a callback method. It’s an essential pattern for being able to integrate C++ or Objective-C objects with a C-based API.
For Image Capture, the code might look like this:
ICAGetDeviceListPB pb = {}; pb.header.refcon = (unsigned long)self; OSErr err = ICAGetDeviceList (&pb, YourDeviceListCallbackHere);
Then in the callback you cast the refcon back to your controller object and go about calling methods and accessing member variables.
void YourDeviceListCallbackHere (ICAHeader* pbHeader) { YourController* ic = (YourController *)pbHeader->refcon; [ic doSomethingUseful:pbHeader]; }
Works fine, but what about 64-bit? The reason I noted this part of the API to blog about was because the first version of my code accidentally cast my pointer to a UInt32. Luckily for us, the refcon is actually declared as an unsigned long instead, so it should share the same pointer size in 64-bit land, where long and void* are both 8 bytes. Other data types in Image Capture, such as ICAObject, are declared to be UInt32.
(What would we do if the refcon was UInt32? The solution is not terribly difficult: use a simple lookup table that maps a random ID or incrementing number stored in the refcon to your 64-bit compatible pointer. But this just doesn’t seem to be necessary very often.)
No delete function. I found this one strange, and had to dig in example code to find the solution. There is no first-class function in Image Capture for deleting objects off of a camera. Apparently this isn’t a feature that is supported by all devices, but nevertheless it seems common enough that it deserves something more than an enum constant hidden in a secondary header file.
Here’s how you go about deleting a video off of the iPhone:
ICAObjectSendMessagePB pb = {}; pb.header.refcon = 0; pb.object = (ICAObject)your_movie_id_here; pb.message.messageType = kICAMessageCameraDeleteOne; OSErr err = ICAObjectSendMessage (&pb, NULL);
Bad delete on success design. Related to the above, Image Capture has this trick that seems clever at first but which I don’t think could be used for most applications. You can set a flag to tell Image Capture to delete a video after it imports. Maybe this also explains why there’s no standalone delete function, but the design feels dangerous to me; if an import fails halfway through importing 10 videos, the first 5 will still be deleted. I much prefer to examine the imported files to make sure they were saved correctly, and then after everything was successful go back and delete the imported objects.
It’s been a couple months since we recorded Core Intuition 21, but there are some other segments worth noting. Daniel and I talked about the WWDC 2009 session videos, a plug for “rooSwitch”:www.roobasoft.com/rooswitch… beta testing MarsEdit 3, and a listener question about working for non-developer managers. Listen at coreint.org or “subscribe in iTunes”:phobos.apple.com/WebObject…