Archive for the 'Documentation' Category

Manpage Monday: PlistBuddy(8)

Monday, April 13th, 2009

PlistBuddy(8) is a command-line tool for editing property-list files, with a deeper reach than plutil defaults:

Entries consist of property key names delimited by colons. Array items are specified by a zero-based integer index. Examples:


Jonathan “Wolf” Rentzsch, in his bookmark for the manpage, says that PlistBuddy is “always at /usr/libexec/PlistBuddy on modern systems”.

Manpage Monday: copyfile(3)

Monday, March 30th, 2009

copyfile(3) is an API for copying and moving files within the file-system:


These functions are used to copy a file’s data and/or metadata. (Metadata consists of permissions, extended attributes, access control lists, and so forth.)

The copyfile() function can copy the named from file to the named to file; the fcopyfile() function does the same, but using the file descriptors of already-opened files.

The copyfile() and fcopyfile() functions can also have their behavior modified by the following flags:


Return a bitmask (corresponding to the flags argument) indicating which contents would be copied; no data are actually copied. (E.g., if flags was set to COPYFILE_CHECK|COPYFILE_METADATA, and the from file had extended attributes but no ACLs, the return value would be COPYFILE_XATTR.)


Serialize the from file. The to file is an AppleDouble-format file.


Unserialize the from file. The from file is an AppleDouble-format file; the to file will have the extended attributes, ACLs, resource fork, and FinderInfo data from the to file, regardless of the flags argument passed in.

File Manager also has APIs for copying files, in both asynchronous and synchronous flavors. Those APIs don’t provide as much control over management of metadata, but they do offer asynchronous operation, whereas the copyfile(3) APIs appear to be synchronous.

And, of course, I should mention NSWorkspace operations, which you use with the performFileOperation:source:destination:files:tag:
. Unlike the other two, this API has been around since 10.0. On the other hand, like copyfile(3), it’s synchronous only.

Manpage Monday: CC_SHA(3cc)

Monday, February 16th, 2009

The Common Crypto library in Mac OS X 10.4 and later provides simple APIs for five SHA algorithms:

CC_SHA1() computes the SHA-1 message digest of the len bytes at data and places it in md (which must have space for CC_SHA1_DIGEST_LENGTH == 20 bytes of output). It returns the md pointer.

CC_SHA1_Init() initializes a CC_SHA1_CTX structure.

CC_SHA1_Update() can be called repeatedly with chunks of the message to be hashed (len bytes at data).

CC_SHA1_Final() places the message digest in md, which must have space for CC_SHA1_DIGEST_LENGTH == 20 bytes of output, and erases the CC_SHA1_CTX.

The successor versions of SHA-1, SHA-2, are also implemented for hash bit lengths of 224, 256, 384, and 512. The functions to call to invoke the larger hash-size versions of the algorithms include the hash size as part of the function names: …


All routines return 1 except for the one-shot routines ( CC_SHA1(), etc.), which return the pointer passed in via the md parameter.

How ClickToFlash works

Thursday, January 29th, 2009

Speaking of everybody’s favorite WebKit plug-in, here’s how it works. This should help you understand how it fails on some sites, and maybe aid you in contributing to its development.

First off, it is a WebKit plug-in; it’s written in Cocoa and uses WebKit’s own plug-in API. It does not use the Netscape plug-in API.

A WebKit plug-in declares a list of MIME media types in its Info.plist bundle. It does this by way of a dictionary of dictionaries:


WebKit only loads a WebKit plug-in when it first encounters some content that it needs the plug-in for. It uses these Info.plist dictionaries to know which plug-in it needs to load. So, in the case of ClickToFlash, it only loads ClickToFlash when it encounters something that is of type application/x-shockwave-flash.

Here’s the brilliant part. Adobe’s Flash Player plug-in actually declares* two MIME media types: application/x-shockwave-flash and application/futuresplash.

You will notice that ClickToFlash only declares one of these.

As it turns out, everybody only uses application/x-shockwave-flash. ClickToFlash exploits this.

When you click on the ClickToFlash view, it modifies the object or embed element that the view represents, changing its type attribute to the other type—the one ClickToFlash doesn’t declare; the one no webpages actually use. WebKit notices this change and looks again for a plug-in to handle the movie. This time, it comes up with only one handler: the real Flash Player plug-in.

There are several reasons why a site may not work with ClickToFlash. I suspect one reason is that they try to interact with the movie via JavaScript; ClickToFlash doesn’t export a script object and wouldn’t be able to communicate with the real Flash Player anyway. The script finds itself talking to a wall, and breakage happens.

So now that you know how ClickToFlash works, maybe you can help fix its bugs?

* Flash Player doesn’t declare its MIME types in its Info.plist; it declares them in a resource file, in ‘STR#’ resource 128. Thanks to WebKit developer Mark Rowe for reminding me to look for a resource.

My CocoaHeads unit testing presentation

Monday, January 5th, 2009

One of the things that’s been keeping me busy lately (too busy, in fact, to keep up Framework Friday and Manpage Monday—sorry about that, and I’ll get back to them when I can) is preparing a video based on the presentation I gave at CocoaHeads last month.

I have now finished it. Its title is simply “Unit testing”.

The subject is unit testing for applications written in Cocoa to run on the Mac. I’m not an iPhone developer, so the video is only generally applicable to iPhone development (as much as it is to any other platform); for specific information about testing on the iPhone, see Colin’s blog post.

I corrected a few things that I got wrong in the original live presentation, and added a few new slides. Other than that, it’s basically the same.

The video is 13+½ minutes long (strangely, about half the length of the original live presentation), and is available in high-definition. You can even download the original file I uploaded, in case you’re so inclined; it uses the lossless Animation codec for the video track, and is 720p and 135.7 MiB.

I used several Creative Commons photographs in the slides. Here are the links back to them:

In other news, I love Keynote’s Instant Alpha feature.

Manpage Monday: notify(3)

Monday, December 8th, 2008

notify(3) is a simple API that allows processes to poke other processes, and to be poked.

The API is similar to NSDistributedNotificationCenter, except that it’s not object-oriented, it’s not based on Foundation or CF, and it doesn’t allow you to attach a property list to the notification.

You register in one of four ways:

Sign up under a name, and get a registration token.
Have the system send your process a signal when another process posts a notification with a particular name. Also get a registration token.
Have the system send your process a message on a Mach port when another process posts a notification with a particular name. Also get a registration token.
Get a registration token, and have the system write that token to a file descriptor when another process posts a notification with a particular name.

Each of the last two functions will create the Mach port or file descriptor for you, unless you tell it to use one you already have. You do that by passing NOTIFY_REUSE.

All four functions give you a registration token (the first one does nothing else), which is simply a signed 32-bit integer. You can then use notify_check to poll that token to see whether any processes have posted a notification to it since the last time you checked. (I don’t know how the other notification methods affect this—e.g., whether notify_check will ever return true if you got the token from notify_register_signal.)

You free the token using notify_cancel. This also closes any Mach ports or file descriptors you have associated with it. There is no way to disassociate them from the token or to cancel the token without closing the associated resources.

On the sending side, the API provides one function: notify_post. It takes one argument, which is the notification name; this is the same name that any receiving processes passed to their chosen notify_register_whatever function.

Leopard adds a new feature: you can associate a shared 64-bit number with a name using notify_set_state, and retrieve that number using notify_get_state. I suggest that you only use notify_set_state in a single process, as I can imagine race conditions occurring if two processes try to set state under the same name. If you need bidirectional communication, use two notification names (or a different means of communication, such as sockets or Mach ports).

Apple introduced the rest of the notify(3) API in Panther.

Updates to “How to work with a bound-to array”

Wednesday, December 3rd, 2008

Following an email conversation with Dave Dribin, I’ve updated my earlier post on how to work with a bound-to array.

The most critical update, and the reason for a new blog post to announce the update, is that you should not currently implement addObject: and removeObject: for an array property. KVO has a bug where it treats these as set accessors, even if the property is an array. This will result in crashes if you observe your object using plain KVO.

The workaround is to use indexed accessors:

[self insertObject:newFramistan inFramistansAtIndex:[self countOfFramistans]];

This is a little uglier than addFramistansObject:, but it doesn’t crash.

The other update is that you need to implement both accessors in a pair. For example, for insertObject:inKeyAtIndex: to work, you must also implement removeObjectFromKeyAtIndex: (and vice versa). Otherwise, KVO won’t override the one you did implement, so you won’t get notifications for it.

I’ve filed bugs for both of these, and I’ve linked to both bugs from the older post.

Framework Friday postponed

Wednesday, November 26th, 2008

The framework I picked turned out to be buggier than usual. Filing those bugs, plus some other things I have on my plate, means I won’t get done anytime close to last Friday.

So, last week’s Framework Friday post will appear on the next Framework Friday instead.


How to work with a bound-to array

Wednesday, November 26th, 2008

You have a model object with an array property:

@property NSArray *framistans;

You also have an array controller whose contentArray binding is bound to this property.

How do you add an object to the array?

Wrong #1: Direct manipulation

[framistans addObject:newFramistan];

The array controller will not notice this change. Worse, the value of your array no longer matches the value your array controller last saw. (For one thing, your array is now one object longer.)

Wrong #2: Use the array controller’s add: action

[arrayController add:nil];

This works, but now you need to go looking for that object. The proper way would be to get the binding info for the array controller’s contentArray binding, then ask the bound-to object for its array, and get the lastObject of that array.

More likely, you’ll hard-code knowledge of which object and which property it’s bound to. Good luck when you change the binding!

Oh, and in a model object, this breaks the separation between your model and everything else. Your model should know nothing of your UI, so that you can replace the UI wholesale if ever you want to (for example, if you make a CLI or web-based version of your app) and keep the same model.

Wrong #3: Add the object to the array controller’s content array

newFramistan = [arrayController newObject];
[arrayController addObject:newFramistan];

This works, and at least you already have the object on hand. But you’re still giving your model knowledge of the array controller, so you’re still breaking separation.

Almost right: Add it to the mutableArrayValue for your property

[[self mutableArrayValueForKey:@"framistans"] addObject:newFramistan];

This works, and it’s clean.

The only problem with it is that it’s too heavyweight: you’re creating this proxy object just to mutate a property. The most appropriate use for mutableArrayValueForKey: is if you want to pass a mutable array to another object, and you want that array to actually be a property of another object. This is a very rare case—I’ve never needed to do it.

For this problem, there is a better solution.

The Right Way: Use your accessor

UPDATE 2008-12-02: Don’t do this. See the section I added below.

[self addFramistansObject:newFramistan];

Look at that.

Beautiful, isn’t it?

It’s almost as short as the direct array access, and it does the Right Thing with KVO. Your array controller will find out about the change without you having to tie knowledge of the array controller into your model.

We should also look at the accessor:

- (void) addFramistansObject:(Framistan *)newFramistan {
    [framistans addObject:newFramistan];

Also short, and also beautiful. (Yes, that is the complete definition of the method. I’m not eliding anything.) And there are no separation violations here, either: It’s pure model.

When you bind the array controller to your object, KVO wraps your object and all its KVC-compliant accessors, including this method. Its implementation performs the proper KVO notifications around a call to your implementation, which means you don’t have to do any KVO work at all.

UPDATE 2008-11-30: Note that you must also implement removeKeyObject:; if you don’t, addKeyObject: will not post the KVO notifications. You must implement both. Thanks to Dave Dribin, who emailed me about this.

ADDED 2008-12-02: The current Right Way: Use indexed accessors

KVO does not work correctly with addKeyObject: and removeKeyObject: for array properties.

The problem is that it treats those methods as set accessors and posts set-mutation notifications, regardless of the fact that it’s an array property. This doesn’t seem to cause a problem with Bindings (as of 10.5.5), but when I tried observing the property using KVO directly, I got a crash every time, as it tried to send NSSet messages to my NSArray.

Instead, you’ll need to use indexed accessors:

[self insertObject:newFramistan inFramistansAtIndex:[self countOfFramistans]];

As with addObject: and removeObject:, you must implement both of the pair. Here’s what removal looks like:

[self removeObjectFromFramistansAtIndex:[self indexOfObjectInFramistans:framistanToRemove]];

indexOfObjectInKey isn’t actually something KVC looks for, but it fits the use case and beats getting the entire array (which generally means copying it) just to find the index of one object. And you have to implement all these methods anyway.

Note that you should not implement addKeyObject: and removeKeyObject: at all for an array property, even to call the indexed methods. That’s because KVO always posts its erroneous set-mutation notifications around your addKeyObject: and removeKeyObject: methods, regardless of how you implemented them.

Thanks again to Dave Dribin, as most of this came up in the same email thread.

Further reading

Manpage Monday: afconvert(1)

Monday, November 24th, 2008

afconvert is a command-line utility that uses Core Audio to convert audio files from one format to another.

The manpage is actually pretty sparse (like the rest of the Core Audio documentation); you’re better off reading the command-line help:

% afconvert -h

A simple example is to convert an AIFF file to AAC in an MPEG-4 file:

% afconvert -f 'm4af' -d 'aac ' -b 98304 Recording.aiff

The resulting file is 96 kbps (98,304 bps) and is named “Recording.m4a”.

UPDATE 2008-11-26: Corrected permalink and title to include the section number.

Framework Friday: OSAKit

Sunday, November 9th, 2008

Apologies for posting this late. I was finishing up the test app and filing relevant bugs.

So, how do you run an AppleScript script?

One way is NSAppleScript. The problem with that is that, in our experience on the Adium project, it leaks memory. Profusely. (Maybe this has changed; Adium has for a long time used a separate process for running AppleScript scripts.)

Another way is to use the Open Scripting Architecture API directly. But that API is pre-Carbon, making it painful to deal with. One specific problem is that the object types aren’t reference-counted.

The third way is OSAScript, one of the classes in OSA Kit.

Wait. OSA Kit?

Yes. OSA Kit is an Objective-C wrapper around the Open Scripting Architecture. Like QTKit (a similar wrapper around QuickTime), it’s a framework in Mac OS X that Apple added in version 10.4. It’s public, but undocumented: As of right now, searching for that name yields exactly five hits, none of which are documentation of OSA Kit.

One of those hits is the list of system frameworks, which says that OSA Kit:

Contains Objective-C interfaces for managing and executing OSA-compliant scripts from your Cocoa applications.

OSA-compliant… like AppleScript!

The interface for OSAScript is the same as that of NSAppleScript, except larger: OSAScript is a superset of NSAppleScript. This is mostly because the OSA supports languages other than AppleScript, such as JavaScript (with this component). Running a script, for example, is no different:

NSDictionary *errorDict = nil;
script = [[[(OSAScript | NSAppleScript) alloc] initWithContentsOfURL:scriptURL error:&errorDict] autorelease];
result = [script executeAndReturnError:&errorDict];

But, unlike NSAppleScript, the OSA Kit does not stop there.

OSA Kit is to Script Editor as Image Kit and PDF Kit are to Preview. Apple removed those applications’ capabilities to a new framework, and rewrote the applications to use the new frameworks. In the process, they added features and made the existing features prettier.

In the case of OSA Kit, the new framework includes classes you can use to build your own Script Editor (or CLImax)—specifically, OSAScriptView and OSAScriptController. You may find these classes useful if you plan to embed some of Script Editor’s functionality into your application.

Of course, you don’t need to use OSA Kit from an application. Here’s a command-line tool I wrote:

File: OSAKit-osascript-1.0.2.tbz

A clone of osascript, written to use either NSAppleScript or OSAScript. The Xcode project contains two targets, one for each version.

There are very few differences between the two variants:

  1. Obviously, the OSA Kit version uses OSAScript, whereas the other version uses NSAppleScript.
  2. The OSA Kit version has an option to allow you to specify the language, and another one to list available languages. (NSAppleScript, as you might guess, only supports AppleScript.)
  3. The OSA Kit version can (theoretically) pass arguments to the script; NSAppleScript doesn’t support this.

OSA Kit does have some downsides:

  1. As I mentioned, it isn’t documented. All we have to go on are the headers.
  2. There’s not even sample code, other than the example I wrote and included in this very post.
  3. Calling a handler by name with arguments doesn’t work (hence the “theoretically” above). I believe that this is a bug in OSAScript; I have filed it, with a summary of -[OSAScript executeHandlerWithName:arguments:error:] always returns an error, never executes the handler.

There is also one potential downside: I don’t know for certain that OSAScript doesn’t leak memory the same way NSAppleScript does (or did). It’s worth trying, though, and it’s more capable anyway.

I consider the OSA Kit to be the future of running AppleScript scripts from Objective-C.

UPDATE 2008-11-09 13:18 PST: Replaced OSAKit osascript 1.0 with 1.0.1, which has a couple more sample scripts.

UPDATE 2008-11-09 17:40 PST: Changed link to CLImax. I had linked to Drew Thaler’s blog post announcing its re-release; now I’m linking to the actual product page, as saved by the Internet Archive’s Wayback Machine.

UPDATE 2008-11-11 20:43 PST: Replaced OSAKit osascript 1.0.1 with 1.0.2, which has better (more GCC-like) error-reporting.

Manpage Monday: backtrace(3)

Monday, October 27th, 2008

New series: Manpage FridayMonday. Every Fridayother Monday, I will post a link to one manpage that comes with Mac OS X. [See update below.]

Today, it’s backtrace(3), which tells you about three functions:


#include <execinfo.h>

backtrace(void** array, int size);

backtrace_symbols(void* const* array, int size);

backtrace_symbols_fd(void* const* array, int size, int fd);


These routines provide a mechanism to examine the current thread’s call stack.

backtrace() writes the function return addresses of the current call stack to the array of pointers referenced by array. At most, size pointers are written. The number of pointers actually written to array is returned.

backtrace_symbols() attempts to transform a call stack obtained by backtrace() into an array of human-readable strings using dladdr(). The array of strings returned has size elements. It is allocated using malloc() and should be released using free(). There is no need to free the individual strings in the array.

backtrace_symbols_fd() performs the same operation as backtrace_symbols(), but the resulting strings are immediately written to the file descriptor fd, and are not returned.

Added 2008-10-25: Here’s a test app to show the output.

File: print_backtrace.tbz


0   print_backtrace                     0x00001fc9 print_backtrace + 31
1   print_backtrace                     0x00001ff6 main + 11
2   print_backtrace                     0x00001f7e start + 54

In order:

  1. Index in the array of addresses
  2. Executable name
  3. Address
  4. Name + offset

UPDATE 2008-10-24 21:19 PDT: I’ve decided to change the schedule on this. Instead of Manpage Friday, I’ll do Manpage Monday, and it will be every two weeks. In between will be Framework Friday.

So this is now the first Manpage Monday post, and I will update its post date on Monday, the 27th. (I can’t update it now because WordPress won’t let me publish a post from the future—only schedule it. Grrr.) The week after that, November 7th will be the first Framework Friday. And in the week after that, November 10th will be the second Manpage Monday.

How to make a RAM disk larger than 2 GiB

Wednesday, August 6th, 2008

UPDATE 2009-09-23: This procedure is no longer necessary since Snow Leopard.

The most frequent question I get about Make RAM Disk is “How do I create a RAM disk larger than 2 GiB?”.

Make RAM Disk uses Mac OS X’s disk images system to do its work. Unfortunately, as of Leopard, the command to create a single RAM disk refuses to create one that is larger than 2 GiB in size, even if you have the RAM to do it.

However, there is a solution.

Jennek Geels, a user who asked the aforementioned question, worked with Jean-Sébastien Rousseau to figure out a solution using Mac OS X’s software-RAID feature. Here’s a refined version of their solution:

  1. dev1=$(basename $(hdiutil attach -nomount ram://$NUMSECTORS))
  2. Repeat step 1 as many times as necessary, changing the variable number each time (dev1, dev2, dev3, and so on).
  3. diskutil createraid stripe $VOLUMENAME HFS+ $dev1 $dev2 .. $devN

So, for example, to create an 8 GiB RAM disk:

  1. NUMSECTORS=4194304
  2. dev1=$(basename $(hdiutil attach -nomount ram://$NUMSECTORS))
  3. dev2=$(basename $(hdiutil attach -nomount ram://$NUMSECTORS))
  4. dev3=$(basename $(hdiutil attach -nomount ram://$NUMSECTORS))
  5. dev4=$(basename $(hdiutil attach -nomount ram://$NUMSECTORS))
  6. diskutil createRAID stripe $VOLUMENAME HFS+ $dev1 $dev2 $dev3 $dev4

diskutil createRAID will format and mount the RAID device automatically; you don’t need to run newfs_hfs and diskutil mount like you do when creating a single-device RAM disk.

I tested the speed briefly (just one run each, not averaged over several runs). Copying 2,000 MiB from /dev/zero to an 8 GiB RAIDed RAM disk was about one second faster (~5 seconds) than copying it to a 2 GiB single RAM disk (~6 seconds). Your results may vary.

When you’re done, you’ll need to eject all of the devices separately, starting with the RAID:

  1. diskutil eject $RAIDDEVICE
  2. hdiutil detach $dev1
  3. hdiutil detach $dev2
  4. ..
  5. hdiutil detach $devN

If you don’t remember the device name of the RAID device, you can look it up in the output of diskutil listRAID. Look for the line labeled “Device Node:”.

I have no immediate plans to add this RAID feature to Make RAM Disk, because I’d also need to write an app to handle the full clean-up procedure. For now, if you really need a RAM disk that big, you can probably handle creating it and tearing it down yourself.

What to do if Python says “character mapping must return integer, None or unicode”

Monday, June 16th, 2008

So you’re using the unicode class’s translate method, and it says:

TypeError: character mapping must return integer, None or unicode

You may be wondering what causes this. After all, you’re duly using the string.maketrans function. Surely this should be valid?

Well, no: You can only use string.maketrans with str.translate. For unicode.translate, you must use a different kind of translation table:

… a mapping of Unicode ordinals to Unicode ordinals [int], Unicode strings [unicode] or None.

3.6.1 String Methods

In Localization Helper, I had to replace my string.maketrans call with this code:

dict(zip(map(ord, u'\a\b\t\n\v\f\r'), u'abtnvfr'))

Note that I need to call ord on each key character, because keys must be ints.

Things your ReadMe must include

Tuesday, May 20th, 2008
  • The name of your application
  • What it does
  • How to configure the application, if necessary (note: does not include installation)
  • Simple overview of how to use the software, once it’s configured (detailed manual should be in the Help menu)
  • How to uninstall the software, if necessary (i.e., if it isn’t an application)
  • FAQ
  • What it costs, if it’s not free
  • How to register it
  • A link to your website (in case a magazine distributes your app on its CD)
  • Contact information for support questions
  • Contact information for sales (registration/pricing/currency) questions

Things that you may want to include, but aren’t necessary

  • Screenshots
  • Troubleshooting information

Things that you shouldn’t include

  • Installation instructions: If it’s a plain app, you don’t need an installer; otherwise, make an Installer .pkg. In either case, you shouldn’t need instructions.

Formats I approve

  • RTF or RTFd
  • HTML or webarchive
  • Plain text

You may also want to provide a trampoline application to open a localized version of your ReadMe (for example, see the ReadMe on the Mac OS X DVD). Bonus points if you create a kit to make these, for the benefit of other developers.

Formats I disapprove

  • Word or OOXML format: Many people don’t have Word, and everything else handles these documents imperfectly. Use RTF instead.
  • OpenOffice format: Many (probably most) people don’t have OpenOffice. Use RTF instead.
  • PDF: Use PDF either for vector graphics (inside your app) or for documents you expect someone to print. If the user is going to have to print your ReadMe, you need an interface overhaul.

As usual, I invite suggestions, rebuttals, and amendments.

UPDATE 2008-05-24: Recommended including contact information, as suggested by ssp.

Apple Bug Friday! 74

Friday, February 22nd, 2008

This bug is Typo in syslogd(8) manpage. It was filed on 2008-01-19 at 15:41 PST.


Apple Bug Friday! 73

Friday, February 8th, 2008

This bug is ASL_QUERY_OP_REGEX should be a modifier, not an operator. It was filed on 2008-01-18 at 23:27 PST.


Report-an-Apple-Bug Friday! 71

Friday, January 18th, 2008

This bug is Description of ASL_OPT_NO_DELAY is unclear. It was filed on 2008-01-18 at 17:34 PST.


How to create a RAM disk with the contents of a disk image preloaded

Friday, January 11th, 2008
  1. hdiutil attach -nomount ram://num_sectors

    One sector is 512 bytes. The output of this command is a BSD device path, such as “/dev/disk3”.

    This is the same step 1 as the usual process.

  2. hdiutil attach -nomount path/to/image

    For example, hdiutil attach -nomount Disk\ Images/Adium_1.2.dmg

    The output for a typical disk image is rather longer:

    /dev/disk4              Apple_partition_scheme         
    /dev/disk4s1            Apple_partition_map            
    /dev/disk4s2            Apple_HFS                      

    You want the Apple_HFS one—in this case, /dev/disk4s2.

  3. dd if=disk_image_device_path of=ram_disk_device_path

    Continuing our example: dd if=/dev/disk4s2 of=/dev/disk3

    This copies the bytes from one device to the other. Be very careful which paths you input! You can overwrite your hard disk if you specify the wrong number! The safest way is to assemble the command in a text editor first, then paste it into your terminal.

  4. diskutil mount disk3

    You should see the volume from the disk image mount in Finder—only this time, it will be writable (most disk images, of course, aren’t). That’s because this volume is not actually the original disk image; it’s the RAM disk, with the disk image’s contents in it.

  5. diskutil eject disk4

    This is just clean-up. You don’t need the original disk image attached anymore, so now you eject it.

    You can use hdiutil detach instead of diskutil eject, with the same device path as its argument.

Report-an-Apple-Bug Friday! 70

Friday, September 14th, 2007

This bug is Borken implementation of -setNilValueForKey: in Model Object Impl Guide. It was filed on 2007-09-14 at 12:24 PDT.