All The Quickies

Document Sample
All The Quickies Powered By Docstoc
					All The Quickies                                                                                                                    11/20/08 9:07 AM

 All The Quickies
 Borkware » Quickies » All The Quickies

 Welcome everyone from! You can also see new items added in the last week and ordered by
 date to see any new items. There's also an RSS feed for new quickies.

        Changing the 'screen' hotkey (Unix->Tools) [permalink]
        Running emacs inside of screen is made difficult because both want
        to use C-A for something important. C-O (AFAIK so far) isn't too
        useful for my use of emacs, so I use that for screen now:

        screen -e^Oo emacs

        Rejoining a disconnected screen session (Unix->Tools)                              [permalink]

        screen -r

        Backups on the cheap (Unix->General) [permalink]
        I've been using hfstar for doing backups. I tar directory hierarchies to an external firewire
        drive from my TiBook (say my entire $HOME directory, plus the /Applications directory.
        There's probably other stuff that should be snarfed (like /Library), but I didn't on my last
        backup, and doing a restore from scratch seemed to work OK. Here's a quick outline of
        backing up to the external firewire drive called "Wikkit":
              % sudo mkdir /Volumes/Wikkit/backup
              % cd /Users
              % sudo hfstar cf - bork | (cd /Volumes/Wikkit/backup; sudo hfstar
              xf -)
        The tar above is the standard push-pull tar. Both sides are run as root so that owner, group,
        and permissions are preserved for the files.

        To Restore:

                %   cd /Users
                %   sudo mv bork bork-orig
                %   cd /Volumes/Wikkit/backup
                %   sudo hfstar cf - bork | (cd /Users; sudo hfstar xf -)

        Some folks have had success with psync, but we haven't used it yet.

        Case - insensitive file completion with bash (Unix->General) [permalink]
        If you use bash as your shell and use filename completion a lot, you can get bash to ignore
        the case of filenames just like HFS does. Just put this in your ~/.inputrc file:

        set completion-ignore-case On

        Then when you type ls /appli in the shell you'll get ls /Applications/ like you ought to!

        Changing all *.oop files to *.ack (Unix->General)                        [permalink]
        % ~/bin/ 's/.oop$/.ack/' *.oop

        To tack on an extension to all files, do something like % ~/bin/
        's/(.*)/$1.jpg/' *

        Converting from DOS to unix line terminators (Unix->General)                                    [permalink]
        % perl -pi -e 's/\r/\n/g' mealcsv.csv

        Converting mac newlines to unix newlines in a text file (Unix->General)                                       [permalink]

        tr '\r' '\n' < macfile.txt > unixfile.txt

        Daemontools controls (Unix->General) [permalink]
        # svc -d /service/whatever - Bring the server down

        # svc -u /service/whatever - Start the server up and leave it in keepalive mode.

        # svc -o /service/whatever - Start the server up once. Do not restart it if it stops.

        # svc -t /service/whatever - Stop and immediately restart the server.

        # svc -k /service/whatever - Sends the server a KILL signal. This is like KILL -9. If svc
        -t fails to fully kill the process, use this option.

        (Thanks to the OpenACS documentation)

        Dealing with directories with spaces in them (Unix->General)                                   [permalink]
        You can either escape the directory name with a space: % cd
        /Users/bork/Library/Screen\ Savers

        or you can surround it with quotes: % cd "/Users/bork/Library/Screen Savers"

        Note that tilde expansion (~/Library) is suppressed if you use the quotes.

        Deatching another screen session. (Unix->General) [permalink]
        Sometimes if you have an unclean disconnect, screen can still be attached and you get the

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                                                  Page 1 of 57
All The Quickies                                                                                                   11/20/08 9:07 AM


      % screen -r
      There is a screen on:
              8395.pts-0.vikki              (Multi, attached)

      You can boot off that other loser by using:

      % screen -d 8395.pts-0.vikki

      and then doing screen-r again

      Directory space consumption (Unix->General) [permalink]
      To see how much disk space a directory consumes, use
      % du -sk dir_name

      To see how much each of a directory's contents consume, use
      % du -sk dir_name/* | sort -n to get a list ordered by size.

      Doing something to a hierarchy of files (Unix->General) [permalink]
      To do something to all of the html files in a directory (e.g. to grep something)
      % cd directory
      % find . -name "*.h" -exec grep NSDoWhatIMean {} ; -print
      Don't forget the dot right after find, and the {} construct. Also make sure there's a space
      after the {} and ;

      Don't show file names with a multi - file grep (Unix->General)                [permalink]
      use the -h flag:

      % grep -h chicken ~/Documents/ircLogs/FreeNode/2007*/#macsb*

      Finding Mac OS X version from the command line (Unix->General)                       [permalink]
      % sw_vers

      ProductName:    Mac OS X
      ProductVersion: 10.3.7
      BuildVersion:   7S215

      Finding parent process IDs on Linux (Unix->General)             [permalink]
      % ps -eo "%p %P %c"

      Finding suid executables (Unix->General)      [permalink]
      To find setuid executables, run

      % find . -type f -perm +06000 -print

      (or use find / to start looking from the root directory.)

      Getting a count from grep (Unix->General) [permalink]
      To see how many times "fix me" occurs in the Objective-C files in the current directory:
      % grep -c "fix me" *.m

      Getting curl to download a file (Unix->General) [permalink]
      % curl -O

      Getting grep to return file names of matches rather than the actual match (Unix-
      >General) [permalink]
      Use the -l (dash ell) flag to grep. If a file contains the expression, the name of the file
      (rather than the matching line) is displayed. e.g. to open all the files that contain 'rzolf'

      % grep -l rzolf *.ham | xargs open

      Grepping for flags (Unix->General) [permalink]
      Sometimes you want to grep for something like "-H", but don't want it to be interpreted as
      a grep flag. The -e option to the rescue:

      % grep -e -H filename

      Mounting a disk image from the command line (Unix->General)                      [permalink]
      % hdiutil mount diskimage.dmg

      Perl breaks in weird and wonderful(?) ways (Unix->General) [permalink]
      Perl 5.8 uses unicode internally by default, which apparently causes trouble for some big perl
      packages (like SpamAssassin's makefile getting totally trashed when you create it). Set the
      LANG environment variable to be en_US to make it happier.

      Removing files with a leading "- " (Unix->General)          [permalink]
      % rm -- -i-am-a-bad-file

      Replacing a string in a set of files (Unix->General) [permalink]
      % perl -pi.bak -e 's/OLDSTRING/NEWSTRING/g' *.html
      This will leave "*.bak" files around of the original version, in case the replacement string
      didn't quite do what you wanted.

      Restricting Find to only deal with files (not directories) (Unix->General)                     [permalink]
      % find . -type f -name "*.html" -exec grep Spoon {} ; -print

      Running a pipeline in sudo (Unix->General)      [permalink]

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                                 Page 2 of 57
All The Quickies                                                                                          11/20/08 9:07 AM

      % sudo sh -c "tar cf - * | (cd /mirror4/web; tar xf -)"

      Sanity checking an XML file (Unix->General) [permalink]
      % xmllint -noout kipple.xml Handy for a quick check after hand-editing a file.

      Seeing all the flags gcc takes (Unix->General)        [permalink]
      % gcc -v --help

      Seeing the console.log without running (Unix->General)              [permalink]
      In a terminal or an emacs shell:
      % tail -f /var/tmp/console.log

      Seeing the files in a zip archive (Unix->General)        [permalink]
      % unzip -l

      Seeing the parent process id in ps (Unix->General)           [permalink]
      Use the ppid option with the -o flag:

      % ps -axo user,pid,ppid,vsz,tt,state,start,time,command

      Toggle 'screen's visible bell on and off (Unix->General) [permalink]
      Assuming ^t is the hotkey, doing ^t ^g will toggle the visible bell on and off.

      Using "find" with multiple - name clauses (Unix->General) [permalink]
      % find . \( -name "*.jpg" -or -name "*.gif" \) -exec do_something_with
      {} ;

      Using Image Magick to scale an image proportionally (Unix->General) [permalink]
      % find . -name "*.jpg" -exec convert -verbose -geometry 150x150 {} {} ;
      This converts the files in-place, so have a backup. Even though the geometry is specified as
      150x150, that just means make the image no larger than 150 in either direction.

      Using ImageMagick to get the dimensions of a file (Unix->General)             [permalink]
      % identify filename.jpg

      If you want to be studly, you can use -format to tailor the output

      % identify -format "insert into bw_graphics values
      (generate_primary_key(), '/images/llamas/%f', %w, %h);" *.jpg
      generates a sql insert statement for each image.

      Using awk to extract the n'th column (Unix->General) [permalink]
      nm outputs a three-column format. I needed to get the set of defined symbols (in particular
      those that start with __, in tracking down a C++ linking problem), which is the third column.
      awk is good for that. Use $N to get the nth column (zero-index). This pipeline did the trick:

        nm ./oopack.o | awk '{print $2}' | sort | grep __

      (Thanks to DougEDoug for the pointer)

      Using awk to print fields (Unix->General) [permalink]
      Here's a way to have awk print all fields (separated by spaces) from each line, except for
      fields number 1 and 9 (starting with a count of 1):

      % awk '{ for (f=1; f <= NF; f++) { if (f != 1 && f != 9) printf("%s ", $f);} printf("
      ");}' < ook.txt

      Or you can put this at the end of a pipeline instead of directing a text file into the
      command. (courtesy of DougEDoug)

      Using tar to copy across the network (Unix->General) [permalink]
      % tar cf - ./stuff | ssh theOtherMachine "tar xf -"

      cd to directory with a space in its name (Unix->General) [permalink]
      There's two ways to do it. The first is to backslash-escape the spaces:
      % cd /Users/bork/development/cool\ stuff/neat\ things

      The other is to use shell completion to put in the backslashes for you. In the above path, if
      you type
      % cd /Users/bork/development/cool[tab], it'll expand "cool stuff" for you.

      safely copying directories (Unix->General) [permalink]
      cp -R is generally unsafe to copy directories with since it will copy through symbolic links
      rather than just copying the link (newer cp's have an -H flag that will work around this). The
      classic unix way of doing things like this is a push-pull tar:

      % tar cf - dir-name | (cd /destination-dir; tar xf -)

      In English: tar out through a pipe into a subshell that's changed directories, feeding that pipe
      into the tar extraction. If you run both sides of the pipeline as root (via sudo), the file
      owners and permissions will be preserved (which cp won't do)

      tar + xargs for huge numbers of files (Unix->General) [permalink]
      If you have too many files to add to a tarball, you can run into the shell's command
      limitation. If you use xargs + tar cf, you'll not get all of your files added to the tarball. Use
      tar's rf command to append to an archive rather than creating one:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                        Page 3 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

      % find . -name "*.yuck" -print | xargs tar rvf oop.tar

      using ssh (or CVS) without a password (Unix->General) [permalink]
      Suppose you have two machines, the local one (your laptop) and the remote one (the
      honking big server located in Minneapolis that hosts To ssh (or CVS) from the
      laptop to the server without needing a password, perform these steps:
         1. % ssh-keygen -t rsa
            (don't use a passphrase. Just hit return twice)

         2. % scp ~/.ssh/

         3. On the remote machine (gitdown)

            % cat ~/ >> ~/.ssh/authorized_keys

      I can't move or symlink a directory (Unix->Hacks)          [permalink]
      If you get the error

      mv: rename build/ to oopack: Is a directory

      when using mv or ln on the command line, that's a Darwin error. To correct the problem,
      remove the trailing slash from the directory name.

      Printing network traffic (Unix->Hacks)       [permalink]

      % sudo tcpdump -Atq -s 0 -i en1

      -i en1 will display traffic on your airport card. Use en0 (or nothing, for most systems) for
      built-in ethernettage.

      You can add a host line to limit output to a particular host

      % sudo tcpdump -Atq -s 0 -i en1 host

      (thanks to Dan Jalkut for this one)

      Changing a file's modification date (Unix->Random) [permalink]
      Sometimes you're doing work which uses a file's modification time to decide whether you
      want to do something (like don't process today's log file, or remove a really old file). You
      could use a time machine to test this, or use touch. You can specify a specific date or time
      using the format [[CC]YY]MMDDhhmm[.SS]]. Here's an example with alternating bolds to
      make it easier to read:

      % touch -t 200703141536 snork.waffle

      % ls -l snork.waffle
      -rw-r--r--   1 markd         markd     298 Mar 14 15:36 snork.waffle

      Creating a RAM Disk (Unix->Random) [permalink]
      % hdid ram://size where size is the size in bytes. the system will round that number up
      or down as it sees fit.

      Getting OS version from the command line (Unix->Random)                  [permalink]

      % sw_vers -productVersion

      Seeing media types supported by your CD/DVD burner (Unix->Random) [permalink]
      On Panther, you can run /usr/bin/drutil info to get a listing of the kinds of media
      your drive supports. For example, on the 17" iLamp:

      % drutil info
       Vendor   Product                     Rev
       PIONEER DVD-RW DVR-104               A227

          Interconnect:     ATAPI
          SupportLevel:     Apple Shipping
                 Cache:     2000k
              CD-Write:     -R, -RW, BUFE, Test, IndexPts, ISRC
             DVD-Write:     -R, -RW, BUFE, Test
            Strategies:     CD-TAO, CD-SAO, DVD-DAO

      Setting file system attribute flags (Unix->Random) [permalink]
      chflags in Mac OS X works like chattr over in Linux-land. So to make a file immutable
      (can't change it, even if you're the superuser), you can sudo chflags uchg file-
      name(s). To undo it, do sudo chflags nouchg file-name(s)

      Adding a new machine alias via netinfo(e) (Unix->Administration) [permalink]
      The NetInfo Manager utility is painfully slow. Here's how to add a machine via the command
      line. In this case adding the IP for a machine called "tower" (thanks to rzolf)

      # niutil -create . /machines/tower
      # niutil -createprop . /machines/tower ip_address
      # niutil niutil -createprop . /machines/tower serves ./local

      Increasing shared memory limits (Unix->Administration) [permalink]
      Edit /System/Library/StartupItems/SystemTuning/SystemTuning

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                   Page 4 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

      tweak some values, like

      sysctl       -w   kern.sysv.shmmax=167772160 # bytes: 160 megs
      sysctl       -w   kern.sysv.shmmin=1
      sysctl       -w   kern.sysv.shmmni=32
      sysctl       -w   kern.sysv.shmseg=8
      sysctl       -w   kern.sysv.shmall=65536 # 4k pages: 256 megs

      Save, and restart your system.

      On some Panther seeds, you may need to add these things to /etc/rc

      Updating critical system files while preserving the original timestamp (Unix-
      >Administration) [permalink]
      Sometimes you need to edit a file, like /etc/rc, but you want to be able to back out your
      changes. You also want to preserve the original timestamp of the file. That way if you back
      out your change, someone else coming along doesn't have to figure out "why did /etc/rc
      change yesterday, it doesn't look any different?" Here's how:
        1. Move (not copy) the original to a backup name. This will preserve the timestamp: %
           sudo mv rc rc-orig

         2. Copy the original to the usual name: % sudo cp rc-orig rc

         3. make your edits: % sudo vi rc
      If you decide your changes aren't worth keeping, you would move the original back:
      % sudo mv rc-orig rc

      Thereby undoing your changes, and not messing up the timestamp of the original file.

      (mucho thankos to Louis Bertrand for this one)

      Bizarro Error message (Tools->General) [permalink]
      gcc gave me this error:
      cc1obj: error: type '<built-in>' does not have a known size
      without any line number to give a clue what was going on. The error turned out to be having
      an objective-C method with an argument type of (void), a typo that should have been
      (void *).

      Changing a dylib's install name (Tools->General) [permalink]
      A dynamic library has an 'install name', which is where the library will assume it will be
      installed. For things like frameworks that will be stored in an application bundle, the install
      name has something like @executable_path/../blah. Sometimes you get a library from
      someone else (or something generated by a gigantic configure script) and need to change
      the install name. The install_name_tool will do that for you. Say I had a library,
      libbork.dylib, that will end up being placed side-by-side with the executable of a cocoa app,
      this is how I would fix it:

      % install_name_tool -id @executable_path/libbork.dylib ./libbork.dylib

      Resizing Windows in IB (Tools->General) [permalink]
      Resizing complex windows in IB can be a pain because the contents don't reflow when you
      change the window size. If you hold down the control key while resizing, though, the
      contents obey their spring configurations and will resize accordingly. Makes the process a
      whole lot easier.

      Seeing a lot of gcc's #defines (Tools->General)       [permalink]
      % gcc -E -dM -x c /dev/null

      (thanks to xmath on #macdev for this one)

      Seeing what frameworks an application links against (Tools->General) [permalink]
      % otool -L /path/to/

      Weak Linking in a Plugin (Tools->General) [permalink]
      I've got some useful utilities in a .c file that I use for some debugging things. And I'm also
      writing a plugin that will go into an app I don't control. I also have a test harness that I can
      load the plugin and do effective debugging. This debugging file has some static variables
      that it uses to control things, like whether to emit log messages, or do other diagnoses.

      The problem is, if I include the usefulStuff.c in my plugin and my test harness, there are
      two copies of the static variables, and the test harness can't control the plugin. If I don't
      include usefulStuff.c in the plugin I get link errors. If I don't declare as weak linked the
      functions I use, I'll get errors when the final program loads the plugin. Sucks to be me.

      Here's one way of doing it (which is kinda hacky, but after spending a day inside of the ld
      man page, and other pain, the fact it works is good enough for me for right now).

      In the source file for the plugin that uses stuff from usefulStuff:

      Declare the function to be weak:

      extern void BWDebugLog (int blah, char *blah) __attribute__((weak_import));

      (you can also do this in your header files. In this case, I didn't want to touch the header)

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                       Page 5 of 57
All The Quickies                                                                                          11/20/08 9:07 AM

      Before you use the function, make sure it's not NULL. Note there's no trailing () after the
      function name.

      if (BWDebugLog != NULL) {
          BWDebugLog (23, "stuff");

      In the Xcode project for the plugin

      Add the flags -flat_namespace and -undefined dynamic_lookup to the "Other Linker
      Flags" (a.k.a. OTHER_LDFLAGS). The flat namespace lets the symbols be found in the test
      harness when the plugin is loaded. The undefined dynamic_lookup means to suppress
      warnings about undefined symbols. This could conceivably mask errors, but it's no worse
      than ZeroLink.

      In the Xcode project for the test harness

      Add usefulStuff.c, and turn on the "Preserve Private External Symbols" checkbox (a.k.a
      -keep_private_externs). That turns the symbol BWDebugLog (and others) into exported
      symbols that'll be visible to the plugin. Otherwise the plugin will never get past that !=
      NULL check earlier.

      Once all that's done, my plugin loads into the test harness and can get controlled. It can be
      loaded into the Real App without undefined symbol errors.

      wrong kind of tag compiler error. (Tools->Random) [permalink]
      This one stumped me for awhile:
      BWNagType.h:23: `BWConcreteType' defined as wrong kind of tag

      In this particular case, I had a type I had declared with:
      @class BWConcreteType; and later on I had decided to turn it into an enum:
      typedef enum BWConcreteType { ... } BWConcreteType;
      without removing the previous @class declaration. So be on the look out for conflicting
      types for the same symbol.

      Building projects from the command line (Project Builder->General) [permalink]
      Look at xcodebuild. We've got a rant about cocoa development in emacs, which includes
      a discussion of pbxbuild, the predecessor to xcodebuild. Some of the arguments have
      changed over the years. I usually run it like:

      % xcodebuild -configuration "Debug" -target "My Groovy App"

      If you have one target, or have a default target, you can leave out the -target argument.

      Defaults- writing an array (General->General)   [permalink]

      % defaults write com.borkware.snongflozzle ookook -array thing1 thing2 thing3

      Discovering when exiting a sub event loop (General->General) [permalink]
      [self performSelector: @selector(whatever) withObject: nil afterDelay:

      The selector gets posted after a sub event loop finishes. You can use this for finding out
      when a live slider is done being manipulated, for instance

      Easy command - line argument handling (General->General) [permalink]
      You can use NSUserDefaults to sniff your command line. So using something like this:

            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            gridType = [defaults objectForKey: @"gridType"];

      Will have the value of "flarn" whether you do something like

      % defaults write com.borkware.BorkStitch gridType flarn


      % ./build/Debug/ -gridType flarn

      Giving the event loop some love (General->General) [permalink]
      Say you're in a callback environment in the main thread, but need to update the UI, like to
      update a progress meter. You can give the runloop a chance to do one flip by doing:

      void giveSomeLove ()
          // give the app some love so it'll update the window
          [[NSRunLoop currentRunLoop] runUntilDate: [NSDate distantPast]];
      } // giveSomeLove

      Iterating through an NSIndexSet (General->General)            [permalink]

      unsigned index;
      for (index = [indexSet firstIndex];
             index != NSNotFound; index = [indexSet indexGreaterThanIndex: index])                    {

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                        Page 6 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

      (courtesy of mikeash)

      Loading a nib file (General->General)   [permalink]

      if ([NSBundle loadNibNamed: @"theNibName.nib"                        owner: self]) {
          ... life is happy
      } else {
          ... couldn't load the nib

      Make an NSValue out of an NSRect (General->General)              [permalink]

            NSRect selectionRect = ...;
            NSValue *value;
            value = [NSValue valueWithRect: selectionRect];

      Making a moby file out of a hierarchy (General->General)             [permalink]

      % find . -name "*.h" -print -exec cat {} \; > ~/moby-file.h

      Open path sheet in the Finder (General->General) [permalink]
      Open a Finder window, then type command-shift-g. Works in standard file dialogs too.

      Reading a file as an NSData (General->General)         [permalink]

            NSString *filename = @"/this/is/my/file/path";

            NSData *data;
            data = [NSData dataWithContentsOfFile: filename];

      Using NSInvocation (General->General) [permalink]
      When you have a target and a selector, it's pretty easy to invoke the selector on the target
      if you're passing one or two parameters, with performSelector:, performSelector:withObject:,
      and so on. If you need to pass three arguments, or things that aren't objects, then you need
      to use NSInvocation.

      In this case, the selector being called takes two arguments, one of which is an object, the
      other is an NSTimeInterval. The atIndex: jazz starts with 2 so that the self parameter
      and the selector can be passed to the method.

         NSMethodSignature *signature = [target_ methodSignatureForSelector:selector_];

         NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
         [invocation setSelector:selector_];
         [invocation setTarget:target_];
         [invocation setArgument:&self
         [invocation setArgument:&lastWait_

         [invocation invoke];

      Using an NSOpenPanel (General->General)        [permalink]

            NSOpenPanel *panel = [NSOpenPanel openPanel];

            [panel setPrompt: @"Stuff for the Choose Button"];

            [panel beginSheetForDirectory: nil
                   file: nil
                   types: [NSArray arrayWithObject: @"buf"] // or other file types
                   modalForWindow: window
                   modalDelegate: self
                   didEndSelector: @selector(openPanelDidEnd:returnCode:contextInfo:)
                   contextInfo: nil];

      and the didEndSelector implementation looks kinda like this:

      - (void) openPanelDidEnd: (NSOpenPanel *) sheet
                    returnCode: (int) returnCode
                   contextInfo: (void *) context
          if (returnCode == NSOKButton) {
              NSArray *fileNames = [sheet filenames];

                   NSLog (@"wooOOooot! %@", [fileNames objectAtIndex: 0]);

      } // openPanelDidEnd

      Verifying Localizable.strings (General->General) [permalink]
      if there's an error in Localizable.string, your NSLocalizedString() call will not look
      up the strings in the file. To verify the file, do something like this:

      % pl < Localizable.strings

      show predefined preprocessor macros (General->General)                [permalink]
      % gcc -E -dM - </dev/null

      A Quieter NSLog (General->Hacks)     [permalink]

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                   Page 7 of 57
All The Quickies                                                                                                                11/20/08 9:07 AM

      //    NSLog() writes out entirely too much stuff. Most of the time I'm
      //    not interested in the program name, process ID, and current time
      //    down to the subsecond level.
      //    This takes an NSString with printf-style format, and outputs it.
      //    regular old printf can't be used instead because it doesn't
      //    support the '%@' format option.

      void QuietLog (NSString *format, ...)
          // get a reference to the arguments on the stack that follow
          // the format paramter
          va_list argList;
          va_start (argList, format);

             // NSString luckily provides us with this handy method which
             // will do all the work for us, including %@
             NSString *string;
             string = [[NSString alloc] initWithFormat: format
                                        arguments: argList];
             va_end (argList);

             // send it to standard out.
             printf ("%s\n", [string UTF8String]);

             [string release];

      } // QuietLog

      Having powerbook not wake from sleep when the lid opens (General->Hacks)
      # pmset lidwake 0

      Converting from a path to an FSRef (General->Random)             [permalink]

           NSString *pathString = ... whatever ...;

           FSRef ref;
           status = FSPathMakeRef ((const UInt8 *)[pathString fileSystemRepresentation],
                                   &ref, NULL);

           if (status != noErr) {
               NSLog (@"bummer. couldn't make FSREf from path '%@'",

      Derezzing resource files (General->Random) [permalink]
      I needed to derez a resource file, with the data living in the resource fork, and get editable
      STR and STR# entities. Here's one way to do it, with the moving pieces in bold.

      % /Developer/Tools/DeRez -useDF             ./blarg.rsrc         /Developer/SDKs/MacOSX10.4u.sdk/Developer/Headers/FlatCarbon/MacTypes.r      > o

      And the reverse process is like:

      % /Developer/Tools/Rez -o blah.rsrc -useDF                   /Developer/SDKs/MacOSX10.4u.sdk/Developer/Headers/FlatCarbon/MacTypes.r oopack2

      Making a Cocoa moby file (General->Random)         [permalink]

      % cat /System/Library/Frameworks/Foundation.framework/Headers/*.h > ~/moby
      % cat /System/Library/Frameworks/AppKit.framework/Headers/*.h >> ~/moby
      % chmod 444 ~/moby

      Varargs in Objective- C (General->Random) [permalink]
      This processes a nil-terminated sequence of strings:

      - (void) snorgWaffle: (NSString *) start, ... {

             va_list argList;
             va_start (argList, start);

             NSString *string = start;

             while (string != nil) {
                 NSLog (@"Done did saw string '%@'", string);

                    string = va_arg (argList, NSString *);

             va_end (argList);

      } // snorgWaffle

      and can be called like

      [self snorgWaffle:@"red", @"planet", @"zeitgeist", nil];

      printf'ing / NSLogging strings without a terminating zero byte (General->Random)

           printf ("hello %.*s\n", 5, "there is no good going on");
           NSLog (@"hello %.*s\n", 5, "there is no good going on");

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                                              Page 8 of 57
All The Quickies                                                                                                   11/20/08 9:07 AM

      results in

      hello there
      2007-05-04 09:14:15.575 printf[4914] hello there

      Similarly, something like printf ("hello %*.*s\n", 10, 5, "florgsnorgle"); will
      right-justify 'florg' in a field of 10 characters.

      (Thanks to TVL for this goodie)

      Am I Being Debugged ? (Debugging->General)       [permalink]

      int AmIBeingDebugged(void)
              int                                                             mib[4];
              struct kinfo_proc                    info;
              size_t                                                 size;

                    mib[0] = CTL_KERN;
                    mib[1] = KERN_PROC;
                    mib[2] = KERN_PROC_PID;
                    mib[3] = getpid();
                    size = sizeof(info);
                    info.kp_proc.p_flag = 0;
                    return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED);

      #define StopIfInDebugger()                    __asm__ volatile ("twnei %0,0" : : "r" (AmIBeingDebugged()))

      (courtesy of arwyn on #macdev. Useful uses: controlling voluminous console output when
      running in gdb, or if running non-debugged, an assert routine that generates stack trace and
      logs it when not-being debugged, but just traps into the debugger at the point of failure
      when being debugged)

      Enabling core files (Debugging->General) [permalink]
      Core files are handy to have around if your program crashes with a SEGV, bus error, or if it
      raises an abort(). You can dig into the core file with gdb There are two ways to enable core
             in your C shell do
             % limit coredumpsize unlimited
             (you can put this into your .cshrc. I don't know what to do for bash)

             Or in your program do
             struct rlimit corelimit = { RLIM_INFINITY, RLIM_INFINITY };
             setrlimit (RLIMIT_CORE, &corelimit); You may need to also add
             #include <sys/types.h>
             #include <sys/time.h>
             #include <sys/resource.h>

      Core files seem to be getting dumped into /cores, rather than the directory the program
      was run from.

      NSDebug.h (Debugging->General) [permalink]
      Take a look at
      /System/Library/Frameworks/Foundation.framework/Headers/NSDebug.h. Lots
      of low-level unsupported APIs for mucking around with gory technical details.

      Turning off Panther's "Program quit - send a report to Apple" dialog (Debugging-
      >General) [permalink]
      During development, it's annoying to get the "Your program just crashed! Send a report to
      Apple?". You can turn that off by entering this in the terminal:

      % defaults write DialogType none

      Turn turn it back on, replace none with prompt to get the original behavior. See for details.

      Breaking on "Deallocation of a pointer not malloced" messages (Debugging->gdb)
      Put a breakpoint on fprintf

      Eating Brains (Debugging->gdb) [permalink]
      You can turn on Zombies to catch uses of objects after they have been released. Here's an
      easy way to do it in the gdb console:

          % gdb     build/Debug/
          (gdb)     set env NSZombieEnabled=YES
          (gdb)     fb -[_NSZombie methodSignatureForSelector:]
          (gdb)     run

      Then exercise your app and trip the error.

      Get a stack trace of all threads (Debugging->gdb)         [permalink]
      (gdb) thread apply all where

      Setting a breakpoint before shared libraries are loaded (Debugging->gdb) [permalink]
      Need to set a breakpoint, say on a Cocoa library function, or something in a shared library

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                                 Page 9 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

      Need to set a breakpoint, say on a Cocoa library function, or something in a shared library
      you're loading later? Set a "f uture b reakpoint":
      (gdb) fb -[NSTextView drawRect:]

      Tracing message sends using gdb (Debugging->gdb)          [permalink]

      b objc_msgSend
      printf "%c[%s %s]\n", $r3&&((id)$r3)->isa->info&2?'+':'-', $r3?((id)$r3)->isa->name:"nil", $r4
      b objc_msgSend_rtp
      printf "%c[%s %s]\n", $r3&&((id)$r3)->isa->info&2?'+':'-', $r3?((id)$r3)->isa->name:"nil", $r4

      And you'll get some output like this:

      -[NSTableColumn _bindingAdaptor]
      +[NSBinder binderClassesForObject:]
      +[NSBinder _allBinderClasses]
      +[NSDisplayPatternTitleBinder isUsableWithObject:]
      +[NSBox self]

      (courtesy of Rob Mayoff)

      Break on szone_error not working (gdb->General) [permalink]
      Sometimes when you have memory corruption issues, the malloc library happily informs you:

      Borkdoku(11062,0xcec0600) malloc: *** error for object 0xd109010:
         incorrect checksum for freed object - object was probably modified
         after being freed, break at szone_error to debug

      Which is fine and dandy, but it lies. I've never gotten szone_error to actually do anything.
      Try breaking on malloc_printf instead.

      Breaking on exceptions (gdb->General) [permalink]
      It can be annoying tracking down the cause of thrown exceptions in Cocoa. you get a notice
      like 2007-05-05 17:18:00.702 QueenStitcher[2804:117] *** Assertion
      failure in -[NSColorWell setColor:], NSColorWell.m:497, u suk l0s3r, and
      then the runloop happily runs again, giving you no clue where the problem is. I tell gdb to
      always break on Cocoa exceptions:

      fb -[NSException raise]
      fb objc_exception_throw()

      For maximal enjoyment, add these two lines to your ~/.gdbinit file, so they'll get set no
      matter how you invoke gdb (no need to add these to every single project, for instance).

      I've been told VoiceOver uses exceptions heavily, so if you're doing VoiceOver development,
      these breaks may cause you pain.

      Displaying four - character ints (gdb->General) [permalink]
      Old-school Mac programming (and Quicktime, and other places) use four-character ints,
      things like 'bork'. You can have gdb print them out if you need to look at one or two of

      (gdb) print/T 1936746868
      $4 = 'spit'

      (thanks to Daniel Jalkut for the print/T trick)

      Finding 'self' on Intel (gdb->General)    [permalink]
      (gdb) po *(int*)($ebp+8)

      Ignoring signals (gdb->General) [permalink]
      (gdb) handle SIGTRAP nostop

      The signal still goes to your program. Another handy option is 'ignore' to prevent it coming
      to the program. Also there is 'print' to print a message go on.

      Printing method arguments (gdb->General) [permalink]
      If you've hit a breakpoint on a method that doesn't have debug symbols, you can sometimes
      get useful information by looking in the processor registers. Arguments start in $r3 and go
      up from there. For Objective-C method sends, $r3 has 'self', and $r4 has the name of the
      method. Subsequent arguments are in $5 and so on.

      (gdb) print (char*) $r4
      $5 = 0x90874160 "drawRect:"

      (gdb) po $r5
      <BWStitchView: 0x1a6670>

      Printing object retain count in gdb (gdb->General)      [permalink]
      In the gdb console:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 10 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

      In the gdb console:
      (gdb) print (int)[theObject retainCount]

      If you're expecting to have an excessively high number of retains, you can use (unsigned
      int) in the cast. I find (int) a skootch faster to type.

      Printing wide character strings (gdb->General) [permalink]
      gdb won't by default let you print wide character strings. Here is a little bit of gdb code
      that'll let you print them. In case that page moves, here is the relevant stuff. Paste this into
      your .gdbinit and then you can use wchar_print:

      define wchar_print
              echo "

                   set $i = 0
                   while (1 == 1)
                           set $c = (char)(($arg0)[$i++])
                           if ($c == '\0')
                           printf "%c", $c

                   echo "


      document wchar_print
      wchar_print <wstr>
      Print ASCII part of <wstr>, which is a wide character string of type wchar_t*.

      Seeing functions and selectors (gdb->General) [permalink]
      info selectors will show you all of the selectors in the application's symbol table. info
      functions will show you all of the functions. You can supply regular expressions to limit the

      Using libgmalloc in gdb (gdb->General) [permalink]
      libgmalloc puts guard pages at the end of malloc'd blocks of memory, letting you catch
      buffer overruns. (This will hugely inflate your program's working set, and may lead to
      swapping) To turn on libgmalloc in gdb, do this:

      (gdb) set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib

      calling objective - C methods in gdb (gdb->General) [permalink]
      To call an Objective-C method in the gdb console, you have to cast the return type (since
      gdb doesn't really know what the return value is):

      (gdb) call (void)[textField setStringValue: @"Bork"]

      Loading a bundle into a running program (gdb->Hacks) [permalink]
      Sometimes it's handy to load a bundle into a running app to do some poseAsClass: for doing
      some debugging or reverse engineering. Make a Cocoa bundle which has the code you want
      to load, then do:

      (gdb) call (id) objc_getClass("NSBundle")
      $1 = (struct objc_object *) 0xa0a051d8

      gdb) call (id)[$1 bundleWithPath:@"/blah/blah/PoseAsClassBundle.bundle"]
      $2 = (struct objc_object *) 0x51467e0

      (gdb) call (BOOL)[$2 load]
      Reading symbols for shared libraries . done

      Disabling control- Z from backgrounding emacs (emacs->General) [permalink]
      I find emacs' control-Z behavior to be pretty annoying (it backgrounds the program if you're
      in a shell, or hides the window if you're in X). Add this to your .emacs file:
      (global-set-key "C-Z" nil)

      Fixing "no job control in this shell" (emacs->General) [permalink]
      Emacs in Mac OS X 10.1.3 (and other versions) has an annoying habit of having broken
      shells when you do M-x shell. You get an error like "Inappropriate ioctl for device, no job
      control in this shell", which makes interrupting or backgrounding programs in shell mode
      impossible. Domo-kun gave me a one-line patch to the emacs source:
      #define DONT_REOPEN_PTY
      . Add that to darwin.h and build emacs. You can get the emacs source from the Darwin
      projects page. If you'd like a binary, drop us some mail.

      Fixing emacs C mode indenting (emacs->General) [permalink]
      Here's a way to change the C indenting style to a major style, and override some of the pre-
      set values (like how emacs 21 changed the bsd indent level from 4 to 8. Gee thanks guys):

      (setq c-default-style "bsd"
            c-basic-offset 4)

      Fixing emacs backspace in screen (emacs->General) [permalink]
      When running emacs insde of screen, screen helpfully turns the backspace/delete key into

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 11 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

      When running emacs insde of screen, screen helpfully turns the backspace/delete key into
      "^[[3~", which gets turned into a forward-delete. Unfortunately, just bashing deletechar
      into backward-delete-char-untabify causes backspace in incremental search to cancel
      the search, which is annoying.

      One option is to set the TERM env var to rxvt:

      % setenv TERM rxvt

      Before cranking up screen.

      Macro    recording (emacs->General) [permalink]
      C-x (    : start recording keyboard macro
      C-x )    : stop recording keyboard macro
      C-x e    : replay current keyboard macro

      Make emacs indent code with spaces instead of tabs (emacs->General) [permalink]
      Personally, I prefer emacs' default indentation with a mixture of tabs and spaces. If you're
      working on a project or for a client that requires indentation with spaces, add this to your
      .emacs file. This will make spaces the indent character, and use 4 spaces per indent level,
      for C, C++, and Objective C:

      (setq c-mode-hook
          (function (lambda         ()
                      (setq         indent-tabs-mode nil)
                      (setq         c-indent-level 4))))
      (setq objc-mode-hook
          (function (lambda         ()
                      (setq         indent-tabs-mode nil)
                      (setq         c-indent-level 4))))
      (setq c++-mode-hook
          (function (lambda         ()
                      (setq         indent-tabs-mode nil)
                      (setq         c-indent-level 4))))

      Resetting shell mode's idea of the current working directory (emacs->General)
      Sometimes the shell mode will get confused as to what the current working directory is (like
      if you use aliases to move to a new directory, or if you use the conveniences like !$). M-x
      dirs will tell the shell buffer to figure out what the current working directory is.

      Restrict editing to the region (emacs->General)      [permalink]
      M-x narrow-to-region

      Hides everything not in the current region.

      Revisiting / reloading a file in emacs (emacs->General) [permalink]
      The $Id: $ tags for CVS are nice, but it can be a pain when you're doing lots of checkins
      and have to re-load the file each time. You can either execute M-x revert-bufer or bind
      that to a key, or else use a trick by doing C-x C-v which invokes find-alternate-file,
      but just so happens to have the current buffer name, so you just have to do C-x C-v RET

      Running shell command pasting result back into the buffer (emacs->General)
      So to run uuidgen, for instance:

      C-U M-! ret uuidgen ret

      Scroll line with cursor to the top of the window (emacs->General)            [permalink]
      C-U 0 C-L

      (you can put in another number besides zero to scroll the line with the cursor to that
      particular line in the buffer)

      Setting variables when loading a file (emacs->General) [permalink]
      So say you're working on a project with two-space indents, but most of your other work
      happens with four-space indents. If the two-space crowd is amenable, add this to the
      bottom of the file:

      /* For the emacs weenies in the crowd.
      Local Variables:
         c-basic-offset: 2

      Showing current column position (emacs->General)          [permalink]
      M-x column-number-mode

      Toggling read- only mode in a buffer (emacs->General)          [permalink]
      C-X C-Q

      Turning off command highlighting in shell mode (emacs->General) [permalink]
      Emacs 21, which comes with Mac OS X 10.2, "helpfully" puts into bold the commands you
      execute in the shell. This drives me nuts, so I figured out how to turn it off. Add this to your
      .emacs file:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 12 of 57
All The Quickies                                                                                          11/20/08 9:07 AM

      (setq comint-highlight-input nil)

      Turning off font - lock mode everywhere (emacs->General)            [permalink]
      (global-font-lock-mode -1)

      Turning off incremental - search highlighting (emacs->General) [permalink]
      Emacs 21, which comes with Mac OS X 10.2, has highlighting enabled when doing
      incremental search (which drives me nuts). You can turn that off by setting this in your
      .emacs file:

      (setq search-highlight nil)

      You may also need to
      (setq isearch-lazy-highlight nil)

      To turn off underlining of matching results. Only some OS X installs need this setting.

      Turning off scroll - to- end in shell- mode (emacs->General)        [permalink]
      (setq comint-scroll-show-maximum-output nil)

      Undo within a given region (emacs->General)         [permalink]
      C-U C-_

      Unnarrowing the region (emacs->General)        [permalink]
      M-x widen

      Use only spaces when indenting code (emacs->General)              [permalink]
      (setq indent-tabs-mode nil)

      Using carriage returns in query - replace / replace- string (emacs->General) [permalink]
      Use C-Q C-J (control-Q control-J) each time you want to include a carriage return. e.g. to
      double-space everything

      M-x replace-string RET C-Q C-J RET C-Q C-J C-Q C-J RET

      Or to put "bloogie " at the beginning of every line

      M-x replace-string RET C-Q C-J RET C-Q C-J b l o o g i e SPACE RET

      compiling emacs .el files (emacs->General) [permalink]
      Big emacs .el files take a long time to load. You can compile them into .elc files by using:
      % emacs -batch -f batch-byte-compile filename.el

      Doing Sheets (NSWindow->General) [permalink]
      To show a sheet in a window, use NSApplication to kick it off:

            [NSApp beginSheet: saveSheet
                   modalForWindow: window
                   modalDelegate: self
                   didEndSelector: @selector(saveSheetDidEnd:returnCode:contextInfo:)
                   contextInfo: NULL];

      In the controls in the sheet, use something like

            [NSApp endSheet: saveSheet           returnCode: NSOKButton];

      To invoke the didEndSelector. Inside of that method, you can check the return code and
      decide what to do:

      - (void) saveSheetDidEnd: (NSWindow *) sheet
                     returnCode: (int) returnCode
                   contextInfo: (void *) contextInfo
          if (returnCode == NSOKButton) {
              // ...
          } else if (returnCode == NSCancelButton) {
              // ...
          } else {
              // ...

            [sheet close];

      } // saveSheetDidEnd

      Finding the height of the title bar (NSWindow->General) [permalink]
      When you setFrame: for a window, you have to account for the height of the title bar. In
      the Classic days it was 16 pixels. In Aqua-land, it's currently 22 pixels. But that's not safe to
      use, so try this instead:

      - (float) titleBarHeight
          NSRect frame = NSMakeRect (0, 0, 100, 100);

            NSRect contentRect;
            contentRect = [NSWindow contentRectForFrameRect: frame
                                    styleMask: NSTitledWindowMask];

            return (frame.size.height - contentRect.size.height);

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                       Page 13 of 57
All The Quickies                                                                                      11/20/08 9:07 AM

      } // titleBarHeight

      Rainer Brockerhoff points out that this might miss any system-suppled window decorations
      at the bottom of the window. There aren't any now, but Mac OS X 10.37 Sabertooth might,
      so you may want to take into account the y positions of the original rectangle and the
      newly calculated content rect.

      Force an NSWindowController's nib to be loaded (NSWindow->General) [permalink]
      The window controller nib doesn't get loaded until the window is manipulated. This can
      cause confusion if you do any kind of setup before the window is shown. If you call the
      window method, that will force the nib file to be loaded. Something like this:

      + (BWInspector *) sharedInspector
          static BWInspector *s_inspector;

             if (s_inspector == nil) {
                 s_inspector = [[BWInspector alloc]
                                   initWithWindowNibName: @"BWInspector"];
                 assert (s_inspector != nil);

                    // force loading of nib
                    (void) [s_inspector window];

             return (s_inspector);

      } // sharedInspector

      Help! My Sheet won't go away (NSWindow->General) [permalink]
      You may need to call [sheet close] in addition to your [NSApp endSheet: sheet

      Making a floating palette (NSWindow->General) [permalink]
      To make a floating palette with small controls, make the palette an NSPanel, and n IB make
      it a "Utility Window".

      Making a panel not eat the key (NSWindow->General) [permalink]
      The default settings for an NSPanel in IB cause the panel to take the main window out of the
      responder chain, and so commands (like undo) don't propagate to the window the inspector
      is editing. In IB, make sure the settings "Utility window" and "Non Activating Panel" are

      Preventing NSPanels from hiding on program deactivation (NSWindow->General)
      Sometimes you want an NSPanel for the nice skinny title bar, but don't want it to hide when
      another program is made active. Somewhere convenient (like in the awakeFromNib), do
      something like

      [panel setHidesOnDeactivate: NO];

      Resizing a window with animation (NSWindow->General) [permalink]
      Use setFrame:display:animate: to resize a window, and have the window animate
      between the two sizes. Remember that Cocoa uses a bottom-left origin, which is a pain
      when dealing with windows. You want the window's top left to be the same between the old
      and new sizes, so you have to dink with the origin as well as the size:

             float delta = ... how much to make the window bigger or smaller ...;
             NSRect frame = [window frame];

             frame.origin.y -= delta;
             frame.size.height += delta;

             [window setFrame: frame
                      display: YES
                      animate: YES];

      Resizing a window with animation and cool cross- fade effect with views
      (NSWindow->General) [permalink]
      NSViewAnimation lets you resize a window and cross-fade some views in one operation.
      (note I've had problems with the window size getting a couple of pixels off using this.
      Hopefully either I'm doing something dumb, or Apple fixes a bug). This code resizes the
      window, and changes the view that lives inside of a box. This is like how the Pages inspector
      works (except Pages doesn't do the gratuitous animation effect)

             NSRect newWindowFrame = ... the new window size;

             NSDictionary *windowResize;
             windowResize = [NSDictionary dictionaryWithObjectsAndKeys:
                                          window, NSViewAnimationTargetKey,
                                          [NSValue valueWithRect: newWindowFrame],

             NSDictionary *oldFadeOut = nil;
             if (oldView != nil) {

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                   Page 14 of 57
All The Quickies                                                                                   11/20/08 9:07 AM

                   oldFadeOut = [NSDictionary dictionaryWithObjectsAndKeys:
                                              oldView, NSViewAnimationTargetKey,
                                              NSViewAnimationEffectKey, nil];

            NSDictionary *newFadeIn;
            newFadeIn = [NSDictionary dictionaryWithObjectsAndKeys:
                                          newView, NSViewAnimationTargetKey,
                                      NSViewAnimationEffectKey, nil];

            NSArray *animations;
            animations = [NSArray arrayWithObjects:
                                      windowResize, newFadeIn, oldFadeOut, nil];

            NSViewAnimation *animation;
            animation = [[NSViewAnimation alloc]
                            initWithViewAnimations: animations];

            [animation setAnimationBlockingMode: NSAnimationBlocking];
            [animation setDuration: 0.5]; // or however long you want it for

            [animation startAnimation]; // because it's blocking, once it returns, we're done

            [animation release];

      Running a window modally (NSWindow->General)           [permalink]

         // I am the very modal of a modern major general.
         int blah = [NSApp runModalForWindow:[self window]];

      and then elsewhere, like in your OK or cancel button

         [NSApp stopModalWithCode:NSOKButton];

      Using an NSWIndowController to load a window (NSWindow->General) [permalink]
      Here's how I like doing things. First make a subclass of NSWindowController:

      @interface BWInspector : NSWindowController
          // ivars, IBOutlets, etc

      // IBActions, etc

      + (BWInspector *) sharedInspector;
      @end // BWInspector

      Then make a nib file with the window, the controls, and other fun stuff you want. This one
      lives in English.lproj/BWInspector.nib

      Then in that class method load the window:

      + (BWInspector *) sharedInspector
          static BWInspector *g_inspector;

            if (g_inspector == nil) {
                g_inspector = [[BWInspector alloc]
                                  initWithWindowNibName: @"BWInspector"];

                   assert (g_inspector != nil); // or other error handling

                   [g_inspector showWindow: self];

            return (g_inspector);

      } // sharedInspector

      That will load the nib file, set up the connections and then open the window for display

      I want my window's background to be yellow (NSWindow->Hacks) [permalink]
      Why you'd want to do that, I don't know, but someone asked me how to turn the window
      background yellow. Since the window has a contentView NSView in it, this adds a category
      on it that draws the background with a transparent yellow. You also get the pinstripe
      effects. Just put this code anywhere.

      @implementation NSView (BWYellowView)

      - (void) drawRect: (NSRect) rect
          NSColor *transparentYellow;

            rect = [self bounds];

            transparentYellow = [NSColor colorWithCalibratedRed: 1.0
                                         green: 1.0
                                         blue: 0.0

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                Page 15 of 57
All The Quickies                                                                                              11/20/08 9:07 AM

                                         alpha: 0.333];
            [transparentYellow set];
            [NSBezierPath fillRect: rect];

      } // rect

      @end // BWYellowView

      I have no idea how you colorize the titlebar.

      Forwarding key events to another window (NSWindow->Random) [permalink]
      To forward key events to another window, make subclass of NSWindow and override

      - (void) sendEvent: (NSEvent *) anEvent
          if ([anEvent type] == NSKeyDown) {
              [someOtherWindow sendEvent: anEvent];

            } else {
                [super sendEvent: anEvent];

      } // sendEvent

      It's up to you to figure out what "someOtherWindow" is, whether it's a delegate or an
      instance variable that holds the other window.

      Making naked memory autoreleased (Hacks->General) [permalink]
      From the devious mind of Rainer Brockerhoff : given a pointer + length, dynamically allocate
      a copy and make it autoreleased, without (directly) involving cocoa objects. One handy
      usage: giving a plugin a copy of some struct, but be protected against the plugin messing it

      static void *tempCopyOf(void *data,UInt32 size) {
          void *buffer = NULL;
          if (data) {
              buffer = malloc(size);
              if (buffer) {
                  [NSData dataWithBytesNoCopy: buffer length: size                      freeWhenDone: YES];
          return (buffer);

      You can get really fancy and assign buffer to calloc(1, size) if you want to give it
      "pass NULL to get a zero-filled buffer back" semantics.

      Also note this doesn't play well with garbage collection - caveat nerdor. (Thanks to Ken
      Ferry for that note)

      Posing as a class (Hacks->General) [permalink]
      Say you wanted to take a peek at how NSSpellChecker does its thing. You can make a
      subclass, override methods, log interesting stuff, and then send super. Use poseAsClass:
      to hook yourself into the matrix during the +load method:

      @interface BorkSpellChecker : NSSpellChecker
      @end // BorkSpellChecker

      @implementation BorkSpellChecker

      + (void) load
          NSLog (@"posing");
          [self poseAsClass: [NSSpellChecker class]];

      } // load

      - (void) ignoreWord: (NSString *) word inSpellDocumentWithTag: (int) tag
          NSLog (@"ignore word: %@ intag: %d",
                 word, tag);
          [super ignoreWord: word
                 inSpellDocumentWithTag: tag];

      } // ignoreWord

      Making the VPN survive fast user switching. (Hacks->Hacks) [permalink]
      Testing admin vs non admin user scenarios while connected to the mothership VPN is a pain.
      Heres a way to modify the system configuration plist to make the VPN connection survive
      fast user switching.

      Open up Internet Connect, select your VPN icon in the toolbar, and choose options from the
      Connect menu. Uncheck "Disconnect when switching user accounts".

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                           Page 16 of 57
All The Quickies                                                                                        11/20/08 9:07 AM

      Connect menu. Uncheck "Disconnect when switching user accounts".

      Stopping a chirping G5 (Hacks->Random) [permalink]
      Some (many? all?) G5s make a quiet chirping sound at one-second intervals, like a quiet
      cricket. It might also chirp when dragging windows or doing something with expose. If that
      bothers you (like it bothered me), go download CHUD (which you should have already), go
      to the Processor system preference panel, and turn off "allow nap". That may shorten the
      life of your machine. But what that means, I have no idea.

      Checking for modifier keys (NSView->General)          [permalink]
      In your mouseDown:

            if ([event modifierFlags] & NSShiftKeyMask) {
                constrain = YES;

      If you need to check them outside of your mouseDown, dip into carbon:
            GetCurrentEventKeyModifiers returns the modifiers of the last event processed by the
            event dispatcher. This is usually sufficient.
            GetCurrentKeyModifiers returns the hardware state of the modifiers.
      Carbon and AppKit use different constants for the modifiers, however, so you may need to
      convert between them depending on your situation. (Muchos Thankos to Peter Hosey for the
      Carbon trick)

      Converting an event to view coordinates (NSView->General) [permalink]
      NSPoint point = [self convertPoint: [event locationInWindow] fromView:

      Detecting arrow keys (NSView->General)        [permalink]

      - (void) keyDown: (NSEvent *) event
          NSString *characters;
          characters = [event characters];

            unichar character;
            character = [characters characterAtIndex: 0];

            if (character == NSRightArrowFunctionKey) {
                [self moveSelectedBlockBy: 1];

            } else if (character == NSLeftArrowFunctionKey) {
                [self moveSelectedBlockBy: -1];

            }      ... and look at whatever other keys you want

      Finding a subview based on tag (NSView->General) [permalink]
      Sometimes you're in a situation where you need to get ahold of a view and it's not
      convenient to set up stuff in IB (like the object needing to get the view isn't in the nib file
      with the window). You can uses NSView's viewWithTag: to find it.

      Grabbing a view into an image (NSView->General)             [permalink]
      In your NSView subclass:

      [self lockFocus];

      NSBitmapImageRep *bits;
      bits = [[NSBitmapImageRep alloc]
                 initWithFocusedViewRect: [self bounds]];
      [self unlockFocus];

      Then you can add it to an NSImage or save it to a file, or whatever.

      If you want to retain the vectoritude of the drawing, you can use [self
      dataWithPDFInsideRect: [self bounds]], and then make an NSPDFImageRep. Avoid
      the NSEPSImageRep since it makes a trip through NSPDFImageRep along with a slow PS to
      PDF conversion. (Thanks to Peter Hosey for the PDF hint)

      Making a custom event tracking runloop (NSView->General) [permalink]
      Sometimes in your mouse tracking code you want to use the
      NSEventTrackingRunLoopMode, such as you wanting to use an NSNotificationQueue
      to coalesce updates for your own mouse tracking code. I've been sticking a call to this in my
      mouseDown: handler for the cases when I want the secondary run loop

      - (void) runEventTrackingRunLoop
          NSEventType eventType = NSLeftMouseDown;

            unsigned int eventMask = NSLeftMouseDownMask | NSLeftMouseUpMask
                | NSLeftMouseDraggedMask | NSMouseMovedMask;

            while (eventType != NSLeftMouseUp) {
                NSEvent *event;
                event = [NSApp nextEventMatchingMask: eventMask
                                untilDate: [NSDate distantFuture]
                                inMode: NSEventTrackingRunLoopMode

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                     Page 17 of 57
All The Quickies                                                                                        11/20/08 9:07 AM

                                     dequeue: YES];

                   eventType = [event type];

                   if (eventType == NSLeftMouseDragged) {
                       [self mouseDragged: event];

      } // runEventTrackingRunLoop

      (and thanks to Rainer Brockerhof for pointing out a no-op line of code from the original
      version of this)

      Performing relative (grab - hand) scrolling (NSView->General) [permalink]
      Grab-hand scrolling is a handy feature in several apps. It's nice being able to scroll around a
      large document diagonally, fer instance. Here's one way to do it (assuming you have a
      standard NSScrollView -> NSClipView -> YourView setup)

      @interface Blah : NSView
          NSPoint grabOrigin;
          NSPoint scrollOrigin;
      @end // Blah


      @implementation Blah


      - (void) mouseDown: (NSEvent *) event
          // deal in window coordinates. there is a scrolling problem
          // if using view coordinates because view coordinates
          // can get transformed
          grabOrigin = [event locationInWindow];

            NSClipView *contentView;
            contentView = (NSClipView*)[layerView superview];

            scrollOrigin = [contentView bounds].origin;

      } // mouseDown

      - (void) mouseDragged: (NSEvent *) event
          NSPoint mousePoint;
          mousePoint = [event locationInWindow];

            float deltaX, deltaY;
            deltaX = grabOrigin.x - mousePoint.x;
            deltaY = mousePoint.y - grabOrigin.y;

            NSPoint newOrigin;
            newOrigin = NSMakePoint (scrollOrigin.x + deltaX,
                                     scrollOrigin.y + deltaY);

            [layerView scrollPoint: newOrigin];

      } // mouseDragged

      @end // Blah

      You can be fancy and check for the option key by look at [event modifierFlags] and
      looking for NSAlternateKeyMask, and also use the NSCursor open/closedHandCursor.

      Reacting to the Escape key (NSView->General) [permalink]
      There's no predefined constant for the Escape key. Luckily the escape key predates every
      personal computer, and so it has a pretty reliable character value that's generated: 27:

      - (void) keyDown: (NSEvent *) event
          NSString *chars = [event characters];
          unichar character = [chars characterAtIndex: 0];

          if (character == 27) {
              NSLog (@"ESCAPE!");
      } // keyDown

      Reacting to the delete key (NSView->General) [permalink]
      Look for NSDeleteCharacter in the event's character string:

      - (void) keyDown: (NSEvent *) event
          NSString *chars = [event characters];

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                     Page 18 of 57
All The Quickies                                                                                    11/20/08 9:07 AM

             unichar character = [chars characterAtIndex: 0];

          if (character == NSDeleteCharacter) {
              NSLog (@"Delete!");
      } // keyDown

      Responding to modifier keys only (NSView->General) [permalink]
      NSView's keyDown: and keyUp: don't fire when just a modifier key goes down. If you do
      want to react to this, you'll need to override flagsChanged: (NSEvent *) event and
      look at the event there. (flagsChanged: comes from NSResponder, so any responder in the
      responder chain can react to it)

      Setting a cursor for a view (NSView->General) [permalink]
      Sometimes you want to change the cursor for a view, say with a crosshair for a view that
      lets you select a rectangle out of an image. There is no -[NSView setCursor:] call
      (drat!) You can get something similar by adding this to your NSView subclass:

      - (void) resetCursorRects
          [super resetCursorRects];
          [self addCursorRect: [self bounds]
                cursor: [NSCursor crosshairCursor]];

      } // resetCursorRects

      Outlining every view (NSView->Debugging) [permalink]
      You can set the NSShowAllViews default value to have every view outlined. Nested views
      get outlined in different colors.

      Set it "permanently" via

      % defaults write NSShowAllViews YES

      (or whatever your application identifier is), or use the one-shot version:

      /Developer/Applications/ -NSShowAllViews YES

      Becoming firstResponder if you don't have an editable cell (NSView->Hacks)
      You make a custom view, add it to your window in Interface Builder, and you make it the
      first responder. When you run the program, your custom view is not the first responder,
      instead some lame-O textfield has snagged keyboard focus. To address this, override this
      undocumented method:

      - (BOOL) _hasEditableCell
          return (YES);
      } // _hasEditableCell

      This workaround is necessary at least for Mac OS X 10.1.*.

      Access environment variables from Cocoa (Random->General)             [permalink]
      Check out NSProcessInfo's environment method

      Adding Growl Notifications (Random->General) [permalink]
      It's pretty easy adding growl notifications to your app. Download the SDK from
      Set up your Xcode project to copy the Growl.framework into your application bundle.

      Pick a class to be the contact point with Growl. Your AppController class is a good place.
      Import <Growl/Growl.h>

      Set the delegate to the GrowlApplicationBridge:

             [GrowlApplicationBridge setGrowlDelegate: self];

      Doing this will eventually have the registrationDictionaryForGrowl delegate message
      called. Return a dictionary with two arrays (Which can be the same). These are the names of
      the alerts you will be posting. These are human-readable, so you'll want to use a localized
      string (which I've already set in the global variable here:

      - (NSDictionary *) registrationDictionaryForGrowl
          NSArray *notifications;
          notifications = [NSArray arrayWithObject: g_timesUpString];

             NSDictionary *dict;

             dict = [NSDictionary dictionaryWithObjectsAndKeys:
                                      notifications, GROWL_NOTIFICATIONS_ALL,
                                  notifications, GROWL_NOTIFICATIONS_DEFAULT, nil];

             return (dict);

      } // registrationDictionaryForGrowl

      And use this to post a notification:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                 Page 19 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

      [GrowlApplicationBridge notifyWithTitle: @"Woop! Time has expired!"
                              description: @"You have been waiting for 37 minutes"
                              notificationName: g_timesUpString
                              iconData: nil
                              priority: 0
                              isSticky: NO
                              clickContext: nil];

      Consult the SDK documentation for more explanations of the features, but they are pretty

      Converting a Fixed to a float (Random->General)        [permalink]

      float blah = FixedToFloat(someFixedvalue);

      other goodies in FixMath.h

      Disabling Chimera's url completion pop - up (Random->General) [permalink]
      Add this to your ~/Library/Application
      Support/Chimera/Profiles/default/xyz.slt/prefs.js file:

      user_pref("browser.urlbar.autocomplete.enabled", false);

      Easy NSLogging of basic data structures (Random->General) [permalink]
      NSString has a couple of convenience functions for print out basic structures like NSRect
      and NSSize:
           NSStringFromRect (someNSRect);
           NSStringFromPoint (someNSPoint);
           NSStringFromSize (someNSSize);

      Finding things like ~/Library, and ~/Library/Application Services (Random->General)
      NSSearchPathForDirectoriesInDomains is how you find the location of things like
      Library directories, or User directories, and the like (this is the NSSearchPathDirectory).
      The NSSearchPathDomainMask is what domains to find things in. For instance for a
      NSLibraryDirectory, a NSUserDomainMask will give you the path to ~/Library,
      NSSystemDomainMask will give you the path to /System/Library, and so on.

      The directories inside of Library, like "Preferences" and "Application Support" are in English
      in the file system, and the Finder presents localized versions to the user. If you need
      ~/Library/Application Support/Borkware, you can construct it like

           NSMutableString *path;
            path = [[NSMutableString alloc] init];

             // find /User/user-name/Library
             NSArray *directories;
             directories = NSSearchPathForDirectoriesInDomains (NSLibraryDirectory,
                                                                NSUserDomainMask, YES);

             // if you had more than one user domain, you would walk directories and
             // work with each path
             [path appendString: [directories objectAtIndex: 0]];

             [path appendString: @"/Application Support"];
             [path appendString: @"/Borkware"];

      Getting the current user's name (Random->General)           [permalink]
      NSUserName() or NSFullUserName().

      Thanks to Peter Hosey for letting us know about a better API for getting these.

      Putting an image on a disk image's window (Random->General) [permalink]
      To have snazzy disk images that have your logo or picture of your dog appear when you
      open them, do this:
           run disk copy, make a new blank image. I'm calling mine "thingie"
           copy image file to the mounted fake drive (logo.jpg)
           open fake drive, choose Show View Options. Make sure you're just changing the
           current window, and not Everything.
           Choose "picture", select the logo.jpg that's on the thingie drive
           resize your window as appropriate
           run this in the terminal to hide the logo.jpg file
           /Developer/Tools/SetFile -a V /Volumes/thingie/logo.jpg
           eject thingie and re-mount it
           you should now see your image, and no visible picture file icon

      Reducing the size of a .dmg disk image (Random->General) [permalink]
      DiskCopy won't let you create a disk image of less than 5 megabytes (a bit inconvenient for
      packaging a program that's 30K). Image->Convert Image will let you compress the
      image. As a side-effect of the compressed format, this makes the image read-only.

      Reducing verbiage on web pages to make them readable. (Random->General)
      In #macsb IRC one day I was complaining about a rumor site blog posting that was hugely
      long and nearly incomprehensible. I was pointed to the summarization service as a way of
      reducing the brainpower needed to figure out what was going on:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 20 of 57
All The Quickies                                                                                                                          11/20/08 9:07 AM

      reducing the brainpower needed to figure out what was going on:
            Select all the text
            Go to the services menu and select summarization service
            You'll get a window with a slider at the bottom. Move that down all the way to the left
            Amazingly, with 9/10 of blog posts it works REALLY well.
      (thanks to Chris Forsythe for this one)

      Setting environment variables for the gui login session (Random->General) [permalink]
      For environment variables you want set for the user's GUI login session, make a plist called
      ~/.MacOSX/environment.plist. Make the root a Dictionary, and add the key/value pairs
      (all strings) to it. Don't forget to logout and back in.

      Turning off Spotlight (Random->General)       [permalink]
      % sudo mdutil -i off /

      minimal tool (Random->General) [permalink]
      I got tired of looking for this everytime I make a simple one-off tool without using Project

      int main (int argc, char *argv[])
          NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

            [pool release];

      } // main

      And you can compile it on the command line with:

      cc -o test -framework Foundation file-name.m

      Extracting PDF text on the cheap (Random->Hacks) [permalink]
      Sometimes you need the text from a PDF, and copy-pasting from Preview isn't terribly
      reliable. If you really just need text and no formatting, Spotlight can help you out:

      % /usr/bin/mdimport -d2           ../Book.pdf >& oopack.txt

      And edit out the little bit of extra metadata output.

      Fixing strange duplicate symbols (Random->Random) [permalink]
      While compiling OpenSP, the SGML parser for OpenJade, I got these errors:

      ld: multiple definitions of symbol OpenSP::Text::~Text [in-charge]()
      Entity.lo definition of OpenSP::Text::~Text [in-charge]() in section (__TEXT,__text)
      Group.lo definition of OpenSP::Text::~Text [in-charge]() in section (__TEXT,__text)
      ld: multiple definitions of symbol OpenSP::Text::~Text [not-in-charge]()
      Entity.lo definition of OpenSP::Text::~Text [not-in-charge]() in section (__TEXT,__text)
      Group.lo definition of OpenSP::Text::~Text [not-in-charge]() in section (__TEXT,__text)
      Param.lo definition of OpenSP::Text::~Text [in-charge]() in section (__TEXT,__text)
      Param.lo definition of OpenSP::Text::~Text [not-in-charge]() in section (__TEXT,__text)

      These are caused by the class in question (Text) not having an explicit destructor declared,
      so the compiler is creating one for us in each of the files. In Text.cxx, add

      Text::~Text() { }

      and in Text.h, add


      to the Text class. (I got it to compile and link, so I didn't go back to check to see if just
      sticking ~Text() {} in Text.h would work.)

      Fixing strange undefined link symbols (Random->Random)            [permalink]
      While building OpenJade, I got these link errors:

      gcc -dynamiclib -o .libs/libogrove.0.0.1.dylib Node.lo LocNode.lo                               -lm -lc -install_name   /usr/local/lib/libogrove.0.dyli
      ld: Undefined symbols:
      vtable for __cxxabiv1::__class_type_info
      vtable for __cxxabiv1::__si_class_type_info
      operator delete(void*)
      operator new(unsigned long)
      /usr/bin/libtool: internal link edit command failed

      The link line needs to have "-lstdc++" added to the end. For OpenJade, edit the libtool script
      and add -lstdc++ to the end archive_cmds line. (but leave it inside the last closing

      Launch Services admin tool (Random->Random) [permalink]
      If you need to poke around Lunch Launch Services, use the lsregister tool that lives in

      Make display plain text messages (Random->Random) [permalink]
      Many HTML emails I receive get rendered in in tiny, tiny point sizes. To have prefer to display plain text instead, quit and run this:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                                                       Page 21 of 57
All The Quickies                                                                                              11/20/08 9:07 AM prefer to display plain text instead, quit and run this:

      % defaults write PreferPlainText -bool TRUE

      Putting an imac to sleep at the login box (Random->Random)             [permalink]
      Press the power button.

      Sending email with .mac when port 25 is blocked (Random->Random) [permalink]
      Say you're at a conference, away from your usual ISP, and you're trying to send email, but
      all port 25 traffic is blocked. Say also you have .mac, for which you keep paying and paying
      and paying to have a reliable external email address, and sending email is also blocked. .mac
      (and perhaps other places) use an alternate port (port 587 in .mac's case) which can be use
      to work around this. Now I can send email, and life is happy.

      Easier Development of Screen Savers (Screen Savers->General) [permalink]
      When you're writing a screen saver, do you find yourself often copying the basted thing to
      your ~/Library/Screen Savers folder? If so, you can make a symbolic link that points to
      your screen saver bundle, and that will automatically get used whenever you engage the
      screen saver engine. e.g.

      % cd ~/Library/Screen Savers
      % ln -s ~/Projects/MonkeySaver/build/Debug/MonkeySaver.saver .

      Finding my resources (Screen Savers->General) [permalink]
      To find resources (say an image) from within the screensaver, use NSBundle bundleForClass.
      So, to get atomsymbol.jpg you would do something like

                    NSBundle *bundle;
                    NSString *path;

                    bundle = [NSBundle bundleForClass: [self class]];
                    path = [bundle pathForResource: @"atomsymbol" ofType: @"jpg"];
                    image = [[NSImage alloc] initWithContentsOfFile: path];

      How about a simple sample or two? (Screen Savers->General) [permalink]
      There's SimpleSaver, a minimal 'bounce a line around the screen' screensaver.
      FullScreenSaver is the same thing, but it bounces the line around the user's desktop instead
      of just a black screen. Also check out Drip, a little more sophisticated (even has a
      configuration panel).

      How do I set the name that's displayed in the preference panel? (Screen Savers-
      >General) [permalink]
      The "Product Name" setting on the Project Builder target has that. Change it by:
        1. open the Targets pane in Project Builder
        2. double-click on your target
        3. go to the Build Settings tab
        4. Edit your Product Name under General Settings

      Where is my preference file ? (Screen Savers->General) [permalink]
      The screen saver preference file lives in the ~/Library/Preferences/ByHost directory.
      The name of the file is the name that you pass to defaultsForModuleWithName:,
      followed by .someBigNumber.plist.

      So, on my machine,

             userPrefs = [ScreenSaverDefaults defaultsForModuleWithName: @"BWDrip"];

      creates a file

      Running a screensaver as your desktop background (Screen Savers->Random)
      In a terminal, run

      -background &

      (all one command)

      Basics (NSTimer->General)    [permalink]

      - (void) handleTimer: (NSTimer *) timer
          do some work here...
      } // handleTimer

      NSTimer *timer;

      timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                       target: self
                       selector: @selector(handleTimer:)
                       userInfo: nil
                       repeats: YES];

      NSTimers and NSTerminateLater (NSTimer->General) [permalink]
      If your application has an open TCP connection to a server and you receive an

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                           Page 22 of 57
All The Quickies                                                                                           11/20/08 9:07 AM

      If your application has an open TCP connection to a server and you receive an
      applicationShouldTerminate: message, you're likely to want to
      returnNSTerminateLater so that you can first gracefully shut down the connection before

      There is a gotcha: returning NSTerminateLater stops the main runloop, so your NSTimers
      will stop working from that point on. Thus, if you were depending on a timer firing to finish
      up your shut-down process, you'll never see it, and you'll hang. The solution is to return
      NSTerminateCancel, then do whatever you need to do and then terminate yourself
      manually. (Thanks to Larry Gerndt for this one!)

      Populating a dictionary with predefined values (NSDictionary->General) [permalink]
      dictionaryWithObjectsAndKeys is handy if you're setting up a defaults preference dictionary
      (or text attributes, or any dictionary) by hand:

            defaults = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithFloat: 25.0], @"density",
                                     [NSNumber numberWithFloat: 40.0], @"rate",

      Changing a file to - kb after it's been added (CVS->General)             [permalink]
      % cvs admin -kb filename

      Checking .nib and .pbproj files into CVS (CVS->General) [permalink]
      You'll need to use the cvswrappers file provided in the devtools. The easiest thing to do is
      to copy it to your homedir and prepend a dot:

      % cp /Developer/Tools/cvswrappers ~/.cvswrappers

      You can also add the contents of that fike to your repository.

      .pbproj files aren't handled by the cvswrappers by default. You'll need to add a line like

      *.pbproj -k 'b' -f '/Developer/Tools/cvs-unwrap %s' -t '/Developer/Tools/cvs-wrap %s %s' -m 'COPY'

      Dealing with the past (CVS->General) [permalink]
      To check out the world as it was 3 days ago:

      % cvs checkout -D "3 days ago" blork

      Or via a date (month/day/year)

      % cvs checkout -D "10/17/2002" fnord

      or recently in time

      % cvs diff -D "1 hour ago" ook.blah

      Getting cvs update to build new directories (CVS->General)               [permalink]
      % cvs update -d [whatever]

      Merging a Branch with new directories in CVS (CVS->General) [permalink]
      When merging a branch back into the trunk (using the update command) be sure to use the
      -d option. Otherwise CVS will just ignore any directories added in the branch.

      % cvs update -Ad #switch to the trunk (if you haven't already)
      % cvs update -d -j branch_name
      [resolve conflicts]
      % cvs commit -m "whatever"

      (Courtesy of Jeremy Stein)

      Recursively adding directories (CVS->General)      [permalink]
      To recursively add stuff in CVS:

      % find . -type d -print | grep -v CVS | xargs cvs add
      % find . -type f -print | grep -v CVS | xargs cvs add

      The first adds the directories, the second adds the files. Filenames with spaces in them
      won't be added, and it won't do the Right Thing with -kb for binary files.

      Showing the log comments between a set of revisions (CVS->General)                     [permalink]
      % cvs log -r1.2:1.5 multiprocessing.txt

      Loading a string from a website (NSURL->General)         [permalink]
      (this will block until it loads)

            NSURL *url;
            NSData *data;
            NSString *blork;
            url = [NSURL URLWithString: @""];
            data = [url resourceDataUsingCache: NO];
            blork = [[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding];

      Loading an image from a website (NSURL->General)           [permalink]
      (this will block until it loads)

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                        Page 23 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

            NSURL *url;
            NSData *data;
            NSImage *blork;
            url = [NSURL URLWithString: @""];
            data = [url resourceDataUsingCache: NO];
            blork = [[NSImage alloc] initWithData: data];

      CGShading (Graphics->General) [permalink]
      CGShading lets you do color ramps. Setting one up is a little complicated, juggling a couple
      of CG data structures and writing the ramping function.

            float domain[2] = { 0.0, 1.0 };     // 1-in function
            float range[8] = { 0.0, 1.0,        // N-out, RGBA
                               0.0, 1.0,
                               0.0, 1.0,
                               0.0, 1.0 };
            CGFunctionCallbacks callbacks = { 0, evaluate, NULL };

            CGFunctionRef shaderFunction;
            shaderFunction = CGFunctionCreate (self,    // info / rock / context
                                               1,       // # of inputs for domain
                                               domain, // domain
                                               4,       // # of inputs for range
                                               range,   // range

            CGColorSpaceRef deviceRGB;
            deviceRGB = CGColorSpaceCreateDeviceRGB ();

            CGShadingRef shader;
            shader = CGShadingCreateAxial (deviceRGB,                      //   colorspace
                                           cgpoint(start),                 //   start of axis
                                           cgpoint(end),                   //   end of axis
                                           shaderFunction,                 //   shader, 1-n, n-out
                                           NO,                             //   extend start
                                           NO);                            //   extend end

            CGContextSaveGState (context); {
                NSRect bounds = [self bounds];
                CGContextClipToRect (context, cgrect(bounds));
                CGContextDrawShading (context, shader);
            } CGContextRestoreGState (context);

            [self drawSpotAt: start size: 4];
            [self drawSpotAt: end size: 4];

            CGFunctionRelease (shaderFunction);
            CGColorSpaceRelease (deviceRGB);
            CGShadingRelease (shader);

      And the evaluator function is given an array of inputs and outputs. Use the in value(s)
      (which run from your domain's start-to-finish values) to generate the out values (which
      should be in the range's start-to-finish values):

      static void evaluate (void *info, const float *in, float *out)
          float thing;
          thing = in[0];

            out[0]   =   thing;
            out[1]   =   thing;
            out[2]   =   thing;
            out[3]   =   1.0;

      } // evaluate

      Draw a string centered in a rectangle (Graphics->General)       [permalink]

            NSString *blah = @"Placeholder Pane";
            NSSize size = [blah sizeWithAttributes: nil];

            NSPoint startPoint;
            startPoint.x = bounds.origin.x + bounds.size.width / 2 - size.width / 2;
            startPoint.y = bounds.origin.y + bounds.size.height / 2 - size.height / 2;

            [blah drawAtPoint: startPoint
                  withAttributes: nil];

      Getting a CGContext from Cocoaland (Graphics->General) [permalink]
      You can use CG (CoreGraphics) functions inside of a Cocoa view - pass the graphics port of
      the current context to the CG functions, like this:

      #define cgrect(nsrect) (*(CGRect *)&(nsrect))

      - (void) drawRect: (NSRect) rect
          NSRect bounds = [self bounds];

            NSGraphicsContext *cocoaContext = [NSGraphicsContext currentContext];
            CGContextRef context = (CGContextRef)[cocoaContext graphicsPort];

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                  Page 24 of 57
All The Quickies                                                                                          11/20/08 9:07 AM

            CGContextSetLineWidth (context, 5.0);

            CGContextBeginPath(context); {
                CGContextAddRect (context, cgrect(bounds));
                CGContextSetRGBFillColor (context, 1.0, 0.9, 0.8, 1.0);
            } CGContextFillPath(context);

      } // drawRect

      Grabbing the bits from the screen (Graphics->General) [permalink]
      (Many thanks to Paul Sobolik for giving us this an updated and more reliable version)

      - (NSImage *) captureScreenImageWithFrame: (NSRect) frame
          // Fetch a graphics port of the screen

            CGrafPtr screenPort = CreateNewPort ();
            Rect screenRect;
            GetPortBounds (screenPort, &screenRect);

            // Make a temporary window as a receptacle

            NSWindow *grabWindow = [[NSWindow alloc] initWithContentRect: frame
                                                      styleMask: NSBorderlessWindowMask
                                                      backing: NSBackingStoreRetained
                                                      defer: NO
                                                      screen: nil];
            CGrafPtr windowPort = GetWindowPort ([grabWindow windowRef]);
            Rect windowRect;
            GetPortBounds (windowPort, &windowRect);
            SetPort (windowPort);

            // Copy the screen to the temporary window

            CopyBits (GetPortBitMapForCopyBits(screenPort),

            // Get the contents of the temporary window into an NSImage

            NSView *grabContentView = [grabWindow contentView];

            [grabContentView lockFocus];
            NSBitmapImageRep *screenRep;
            screenRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: frame];
            [grabContentView unlockFocus];

            NSImage *screenImage = [[NSImage alloc] initWithSize: frame.size];
            [screenImage addRepresentation: screenRep];

            // Clean up
            [grabWindow close];

            return (screenImage);

      } // captureScreenImageWithFrame

      Using CGLayers (Graphics->General) [permalink]
      CGLayer is a Tiger (and beyond) feature that will cache Quartz operations. Kind of like a
      PICT for CG. Make a new layer based on the context you're going to be drawing it in, then
      get a context from the layer, and draw into that. So something like this:

      - (void) makeLayerInContext: (CGContextRef) enclosingContext
          layer = CGLayerCreateWithContext (enclosingContext, CGSizeMake(100, 100),
                                            NULL); // options - unused in Tiger
          CGContextRef context;
          context = CGLayerGetContext (layer);

            // .. and do your drawing

      } // makeLayer

      And then to draw the layer at a particular point (like replicating it a bunch of different points
      as done here):

            for (i = 0; i < pointCount; i++) {
                CGContextDrawLayerAtPoint (context, locations[i], layer);

      Turning a string into a path (Graphics->NSString)       [permalink]

      - (NSBezierPath *) makePathFromString: (NSString *) string
                                    forFont: (NSFont *) font
          NSTextView *textview;
          textview = [[NSTextView alloc] init];

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                       Page 25 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

             [textview setString: string];
             [textview setFont: font];

             NSLayoutManager *layoutManager;
             layoutManager = [textview layoutManager];

             NSRange range;
             range = [layoutManager glyphRangeForCharacterRange:
                                        NSMakeRange (0, [string length])
                                    actualCharacterRange: NULL];
             NSGlyph *glyphs;
             glyphs = (NSGlyph *) malloc (sizeof(NSGlyph)
                                          * (range.length * 2));
             [layoutManager getGlyphs: glyphs range: range];

             NSBezierPath *path;
             path = [NSBezierPath bezierPath];

             [path moveToPoint: NSMakePoint (20.0, 20.0)];
             [path appendBezierPathWithGlyphs: glyphs
                   count: range.length inFont: font];

             free (glyphs);
             [textview release];

             return (path);

      } // makePathFromString

      Disabling "Return moves editing to next cell" in TableView (NSTableView->General)
      When you edit cells in a tableview, pressing return, tab, or shift-tab will end the current
      editing (which is good), and starts editing the next cell. But of times you don't want that to
      happen - the user wants to edit an attribute of a given row, but it doesn't ever want to do
      batch changes to everything.

      To make editing end, you need to subclass NSTableView and add code to catch the
      textDidEndEditing delegate notification, massage the text movement value to be something
      other than the return and tab text movement, and then let NSTableView handle things.

      // make return and tab only end editing, and not cause other cells to edit

      - (void) textDidEndEditing: (NSNotification *) notification
          NSDictionary *userInfo = [notification userInfo];

             int textMovement = [[userInfo valueForKey:@"NSTextMovement"] intValue];

             if (textMovement == NSReturnTextMovement
                 || textMovement == NSTabTextMovement
                 || textMovement == NSBacktabTextMovement) {

                    NSMutableDictionary *newInfo;
                    newInfo = [NSMutableDictionary dictionaryWithDictionary: userInfo];

                    [newInfo setObject: [NSNumber numberWithInt: NSIllegalTextMovement]
                             forKey: @"NSTextMovement"];

                    notification =
                        [NSNotification notificationWithName: [notification name]
                                                   object: [notification object]
                                                   userInfo: newInfo];


             [super textDidEndEditing: notification];
             [[self window] makeFirstResponder:self];

      } // textDidEndEditing

      (Thanks to Steven Jacowski for a tweak that ends editing on clicks on different cells)

      Dragging feedback only between rows (NSTableView->General) [permalink]
      When rearranging rows in a tableview, the user feedback should just go between rows (the
      whole-row highlighting is confusing). In the drop validation method only let things through
      for NSTableViewDropAbove

      - (NSDragOperation) tableView: (NSTableView*) tableView
                       validateDrop: (id ) info
                        proposedRow: (int) row
              proposedDropOperation: (NSTableViewDropOperation) op
          int result = NSDragOperationNone;

             if (op == NSTableViewDropAbove) {
                 result = NSDragOperationMove;

             return (result);

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 26 of 57
All The Quickies                                                                                    11/20/08 9:07 AM

      } // validateDrop

      Handling double- clicks (NSTableView->General) [permalink]
      Use NSTableView's -setDoubleAction: method, and supply it a standard IBAction-style
      method selector.

      You may need to also do -setTarget:. double-clicks get sent if the column isn't editable,
      so you may need to grab the column and do a -setEditable: NO on it.

      Making a table view a drag source (NSTableView->General) [permalink]
      If you want to make your NSTableView a source for a drag and drop operation, you need to

      - (BOOL) tableView: (NSTableView *) view
               writeRows: (NSArray *) rows
            toPasteboard: (NSPasteboard *) pboard

      in your table view data source (and don't forget to hook up the datasource if you use
      bindings to populate the tableview)

      Preventing the return key from editing the next cell (NSTableView->General) [permalink]
      The default tableview behavior, when editing a row, is to move the field editor to the next
      cell when the user commits editing using the Return key. If you want Return to commit the
      editing and dismiss the field editor, subclass NSTableView and add this:

      - (void) textDidEndEditing: (NSNotification *) notification
          NSDictionary *userInfo;
          userInfo = [notification userInfo];

            NSNumber *textMovement;
            textMovement = [userInfo objectForKey: @"NSTextMovement"];

            int movementCode;
            movementCode = [textMovement intValue];

            // see if this a 'pressed-return' instance

            if (movementCode == NSReturnTextMovement) {
                // hijack the notification and pass a different textMovement
                // value

                   textMovement = [NSNumber numberWithInt: NSIllegalTextMovement];

                   NSDictionary *newUserInfo;
                   newUserInfo = [NSDictionary dictionaryWithObject: textMovement
                                               forKey: @"NSTextMovement"];

                   notification = [NSNotification notificationWithName:
                                                      [notification name]
                                                  object: [notification object]
                                                  userInfo: newUserInfo];

            [super textDidEndEditing: notification];

      } // textDidEndEditing

      Putting the ordering triangles in table columns (NSTableView->General) [permalink]
      Put this somewhere (maybe in your mouseDownInHeaderOfTableColumn or

            NSImage *indicatorImage;
            if (sortAscending) {
                sort your data ascending
                indicatorImage = [NSImage imageNamed: @"NSAscendingSortIndicator"];
            } else {
                sort your data descending
                indicatorImage = [NSImage imageNamed: @"NSDescendingSortIndicator"];
            sortAscending = !sortAscending;

            [tableView setIndicatorImage: indicatorImage
                           inTableColumn: tableColumn];

            [tableView reloadData];

      Responding to selection changes (NSTableView->General)       [permalink]

      - (void) tableViewSelectionDidChange: (NSNotification *) notification
          int row;
          row = [tableView selectedRow];

            if (row == -1) {
                do stuff for the no-rows-selected case

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                 Page 27 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

            } else {
                do stuff for the selected row

      } // tableViewSelectionDidChange

      If you have more than one tableview, the notification's object is the tableview that had the
      selection change.

      Table View drag destination on or between rows (NSTableView->General) [permalink]
      When your NSTableView is a drag destination, you may want to support both dragging onto
      existing objects (to replace them, or augment them with some new attribute the user is
      dragging over) and support dragging between existing objects (to insert a new one in
      between. To get this behavior, you need to use NSTableView's -
      setDropRow:dropOperation:, like so:

      - (NSDragOperation) tableView: (NSTableView *) view
                       validateDrop: (id ) info
                        proposedRow: (int) row
              proposedDropOperation: (NSTableViewDropOperation) op
          // have the table highlight on-row / between-row correctly
          [view setDropRow: row
                dropOperation: op];

            // or use whatever drag operation is appropriate
            NSDragOperation dragOp = NSDragOperationCopy;

            return (dragOp);

      } // validateDrop

      and in the acceptDrop method, look at the operation:

      - (BOOL) tableView: (NSTableView *) view
              acceptDrop: (id ) info
                     row: (int) row
           dropOperation: (NSTableViewDropOperation) op
          if (op == NSTableViewDropOn) {
              // replace existing

            } else if (op == NSTableViewDropAbove) {
                // add new

            } else {
                NSLog (@"unexpected operation (%d) in %s",
                       op, __FUNCTION__);

            // documentation doesn't actually say what this signifies
            return (YES);

      } // acceptDrop

      Tableview DataSource methods (NSTableView->General)               [permalink]
      Your datasource needs to implement these two bad boys:

      - (int) numberOfRowsInTableView: (NSTableView *) tableView
      - (id) tableView: (NSTableView *) tableView
      objectValueForTableColumn: (NSTableColumn *) tableColumn
      row: (int) row

      Add pgplsql support (Postgresql->General)     [permalink]
      % createlang plpgsql template1

      Adding a column to a table (Postgresql->General) [permalink]
      alter table pfo_survey_response_2006 add column section text

      Backing up a database (Postgresql->General)      [permalink]
      % pg_dump databasename > db.out

      Connecting to a user / database (Postgresql->General) [permalink]
      Say you have your primary database user as 'nsadmin', and they have a database called
      'openacs'. If you're using the default pg_hba.conf, you can connect to the database,
      logged in as an ordinary person, by doing

      % psql -U nsadmin opeancs

      Creating a new database (Postgresql->General)       [permalink]
      % createdb database-name

      Creating a new user (Postgresql->General) [permalink]
      psql=# create user bork with password 'bork';

      You can also do this for a passwordless user: % crateuser bork

      Inserting a time column (Postgresql->General) [permalink]
      If you have the minutes, seconds, and am/pm and want to get them into a time column
      (time without timezone), you can do something like this:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                  Page 28 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

      (time without timezone), you can do something like this:

      psql=# select to_timestamp('10:45am', 'HH12:MIam')::timetz::time;
      (1 row)

      Limiting selections to X number of rows (Postgresql->General)                   [permalink]
      use the "limit" statement:

      select stuff from some_table
       where stuff.blah > 12
       limit 5

      Logging in as a specific user (Postgresql->General)          [permalink]
      % psql database-name user-name

      Logging into a remote database (Postgresql->General)              [permalink]
      On machine tower, dbname borkdb, user nettest
      % psql -h tower borkdb nettest

      Manually starting the database (Postgresql->General) [permalink]
      % pg_ctl -D /usr/local/pgsql/data -l /tmp/pgsql.log start

      Next value from a sequence (Postgresql->General)         [permalink]

      insert into blah (id, stuff)
             values (nextval('sequence_name'), 'stuff');

      Restoring a Database (Postgresql->General)     [permalink]
      % psql -d databasename -f db.out

      Seeing available databases (Postgresql->General)       [permalink]
      % psql -l
      (lower case Ell)

      Selecting a random row from a table (Postgresql->General)                  [permalink]
      use the random() function.

            select stuff.src, stuff.width, stuff.height from
                (select src, width, height,
                    from bw_eyes
                  order by 4) stuff
            limit 1

      This selects a random row from bw_eyes and returns the interesting data from it. This
      query is used on the quickies pages to randomly select an image of eyes staring back.

      Time interval math to integer (Postgresql->General) [permalink]
      If you take the difference between two timestamps, you can end up with an unweildly value
      like "00:06:14.37086 days old". You can cast the timestamps into just regular dates like:
      select current_timestamp()::date - entry_date::date as days_old from

      Turning off the psql pager (Postgresql->General)       [permalink]
      wplug-oacs=# \pset pager
      Pager usage is off.

      Using tree_sortkey (Postgresql->General) [permalink]
      Jade Rubick has some brief documentation on using the postgresql tree_sortkey stuff.

      pg interval math (Postgresql->General) [permalink]
      Older versions of pg would support select blah from whatever where date-column
      > (current_timestamp - 21) to get all the blahs from whatever in the last 21 days.
      This doesn't work in newer versions of Postgresql. Instead, you need to use a time interval:

      select       to_char (whenx, 'fmDD fmMonth YYYY') as pretty_when, text
        from       blog
       where       whenx > (current_timestamp - interval '21 days')
       order       by whenx desc

      Increasing memory buffer sizes (Postgresql->Administration) [permalink]
      If you try upping your shared_buffers in your postgresql.conf, and get an error
      similar to this:

      IpcMemoryCreate: shmget(key=5432001, size=266371072, 03600) failed:
      Invalid argument
      This error usually means that PostgreSQL's request for a shared memory
      segment exceeded your kernel's SHMMAX parameter.

      You should increase your the shmmax parameters using tips in the Unix
      administration quickies.

      Darwin Website (Darwin->General) [permalink]
      Since I can never remember this, it's at

      Darwin's CVSROOT string (Darwin->CVS)             [permalink]

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                  Page 29 of 57
All The Quickies                                                                           11/20/08 9:07 AM

      for read-only checkouts:

      setenv CVSROOT

      Appending to the end of a textview (NSTextView->General)             [permalink]

            NSRange range;
            range = NSMakeRange ([[textView string] length], 0);

            [textView replaceCharactersInRange: range withString: string];

      And Peter Hosey provided a one-liner that may suit your needs better:

            [[[textView textStorage] mutableString] appendString: string];

      Deleting the selected text (NSTextView->General)         [permalink]
      [textView delete: nil]

      Determining the paragraph style at a particular point (NSTextView-
      >General) [permalink]

      - (NSParagraphStyle *) paragraphStyleInTextView: (NSTextView *) textView
                                              atIndex: (int) index
          NSTextStorage *storage = [textView textStorage];

            NSDictionary *attributes;
            NSRange effectiveRange;
            attributes = [storage attributesAtIndex: index
                                  effectiveRange: &effectiveRange];

            NSParagraphStyle *style;
            style = [attributes valueForKey: NSParagraphStyleAttributeName];

            return (style);

      } // paragraphStyleInTextView

      Finding the span of a paragraph (NSTextView->General) [permalink]
      The NSString paragraphRangeForRange: method gives you the span of a
      paragraph. If you're using the text architecture, you need to get the
      string from the text storage. This chunklet shows the paragraph span
      for the current selection:

            NSRange selectedRange = [textview selectedRange];
            NSTextStorage *storage = [textview textStorage];
            effectiveRange = [[storage string] paragraphRangeForRange: selectedRange];

      Forcing validation of pending text field entries (NSTextView->General)
      [window makeFirstResponder: window]

      Moving insertion point to the end (NSTextView->General)             [permalink]
      NSRange range = { [[textView string] length], 0 };
      [textView setSelectedRange: range];

      Moving insertion point to the start (NSTextView->General)              [permalink]
      NSRange zeroRange = { 0, 0 };
      [textView setSelectedRange: zeroRange];

      Replacing NSTextView's contents with an attributed string (NSTextView-
      >General) [permalink]

                   [[textView textStorage] setAttributedString: theNewString];

      Restricting typed in text to just digits (NSTextView->General)
      Create a subclass of NSNumberFormatter, add this method, and hook up
      the formatter to your text fields.

      - (BOOL) isPartialStringValid:      (NSString **) partialStringPtr
              proposedSelectedRange:      (NSRangePointer) proposedSelRangePtr
                     originalString:      (NSString *) origString
              originalSelectedRange:      (NSRange) origSelRange
                   errorDescription:      (NSString **) error
          NSCharacterSet *nonDigits;
          NSRange newStuff;
          NSString *newStuffString;

            nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
            newStuff = NSMakeRange(origSelRange.location,
                                   - origSelRange.location);
            newStuffString = [*partialStringPtr substringWithRange: newStuff];

            if ([newStuffString rangeOfCharacterFromSet: nonDigits
                     options: NSLiteralSearch].location != NSNotFound) {
                *error = @"Input is not an integer";
                return (NO);
            } else {
                *error = nil;
                return (YES);

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                        Page 30 of 57
All The Quickies                                                                        11/20/08 9:07 AM


      } // isPartialStringValid

      Scrolling to the end of a textview (NSTextView->General)            [permalink]

            NSRange range;
            range = NSMakeRange ([[textView string] length], 0);

            [textView scrollRangeToVisible: range];

      I've heard that scrollRangeToVisible is O(N) for the length of the
      text. So be on the lookout if you have lots of text involved.

      Show NSTextField text in gray if the field is disabled (NSTextView-
      >General) [permalink]
      NSTextField doesn't change its text color if the field is enabled or
      disabled (?) Even more bizarre, using NSColor's
      disabledControlTextColor won't draw the text in the disabled color. You
      need to use the secondarySelectedControlColor, which supposedly is for
      active controls that don't have focus. Go figure.

      To do it yourself, subclass NSTextField and override setEnabled: to
      change the color:

      - (void) setEnabled: (BOOL) flag
          [super setEnabled: flag];

            if (flag == NO) {
                [self setTextColor: [NSColor secondarySelectedControlColor]];
            } else {
                [self setTextColor: [NSColor controlTextColor]];

      } // setEnabled

      This actually kind of a gross workaround for a Cocoa bug - the disabled
      color is getting made darker rather than lighter. The
      secondarySelectedControlColor ends up looking disabled by a happy
      coincidence that it starts out lighter before being darkened. (or
      something like this. UberDude Dave MacLachlan has done the legwork to
      figure out the underlying problem.)

      Truncating text in the middle of a string (NSTextView->General)
      Sometimes you see text that is of the form "Some Gro...eral Fish", with
      the middle truncated but the ends still readable. You can get this
      effect yourself with:

      [[textfield cell] setLineBreakMode: NSLineBreakByTruncatingMiddle]

      (Thanks to Daniel Jalkut for this one)

      scrolling to the beginning of a textview (NSTextView->General)
      NSRange zeroRange = { 0, 0 };
      [textView scrollRangeToVisible: zeroRange];

      Getting the contents of a TextView as an NSString (NSTextView-
      >NSString) [permalink]

      NSString *commitMessage;
      commitMessage = [[commitTextView textStorage] string];

      Changing checkbox toggle state (NSControl->General)         [permalink]
      [myCheckbox setState: NSOffState]

      NSOnState also works.

      Respond to every keystroke in a textfield (NSControl->General)
      Make your object a delegate of the textfield, and add this NSControl
      delegate method:

      - (void) controlTextDidChange: (NSNotification *) notification
          // do work here, like count the characters or something
      } // controlTextDidBeginEditing

      'join' an array of strings into a single string (NSString->General)

      NSArray *chunks = ... get an array, say by splitting it;
      string = [chunks componentsJoinedByString: @" :-) "];

      would produce something like

      oop :-) ack :-) bork :-) greeble :-) ponies

      'split' a string into an array (NSString->General)         [permalink]

         NSString *string = @"oop:ack:bork:greeble:ponies";
         NSArray *chunks = [string componentsSeparatedByString: @":"];

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                     Page 31 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

      Converting string to an integer (NSString->General)                 [permalink]
      NSString *string = ...;
      int value = [string intValue];

      Similarly, there is a floatValue and doubleValue NSString methods.

      Iterating attributes in an attributed string (NSString->General)        [permalink]
      This prints out each of the attribute runs from an attributed string:

      - (void) iterateAttributesForString: (NSAttributedString *) string
          NSDictionary *attributeDict;
          NSRange effectiveRange = { 0, 0 };

            do {
                   NSRange range;
                   range = NSMakeRange (NSMaxRange(effectiveRange),
                                        [string length] - NSMaxRange(effectiveRange));

                   attributeDict = [string attributesAtIndex: range.location
                                           longestEffectiveRange: &effectiveRange
                                           inRange: range];

                   NSLog (@"Range: %@ Attributes: %@",
                          NSStringFromRange(effectiveRange), attributeDict);

            } while (NSMaxRange(effectiveRange) < [string length]);

      } // iterateAttributesForString

      Making localizable strings (NSString->General) [permalink]
      You will need a file named Localizable.strings that lives in your English.lproj
      directory (or whatever localization directory is appropriate). It has this syntax:

      "BorkDown" = "BorkDown";
      "Start Timer" = "Start Timer";
      "Stop Timer" = "Stop Timer";

      That is, a key followed by a localized value.

      In your code, you can then use NSLocalizedString() or one of its variants:

                   [statusItem setTitle: NSLocalizedString(@"BorkDown", nil)];

      The second argument is ignored by the function. Obstensively it is a /* comment */ in the
      strings file so that you can match the key back to what it is supposed to actually be.

      NSLog without the extra crud (NSString->General) [permalink]
      NSlog puts too much crud in front of the logging line. For a foundation tool that output
      stuff, it gets in the way. I'd still like for a replacement to expand %@, which the printf()
      family won't do. Here's a some code that'll do that.

      #include <stdarg.h>

      void LogIt (NSString *format, ...)
          va_list args;

            va_start (args, format);

            NSString *string;

            string = [[NSString alloc] initWithFormat: format                    arguments: args];

            va_end (args);

            printf ("%s\n", [string cString]);

            [string release];

      } // LogIt

      Putting an image into an attributed string (NSString->General)          [permalink]
      You'll need to use a text attachment.

      - (NSAttributedString *) prettyName
          NSTextAttachment *attachment;
          attachment = [[[NSTextAttachment alloc] init] autorelease];
          NSCell *cell = [attachment attachmentCell];

            NSImage *icon = [self icon]; // or wherever you are getting your image
            [cell setImage: icon];

            NSString *name = [self name];
            NSAttributedString *attrname;
            attrname = [[NSAttributedString alloc] initWithString: name];

            NSMutableAttributedString *prettyName;

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                  Page 32 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

            prettyName = (id)[NSMutableAttributedString attributedStringWithAttachment:
                                                        attachment]; // cast to quiet compiler warning
            [prettyName appendAttributedString: attrname];

            return (prettyName);

      } // prettyName

      This puts the image at the front of the string. To put the image in the middle of the string,
      you'll need to create an attributedstring with attachment, and then append that to your final
      attributed string.

      Stripping out newlines from a string (NSString->General) [permalink]
      So you have an NSString and want to yank out the newlines. You can do a splitand join, like
      in scripting languages, or you can make a mutable copy and manipulate that:

            NSMutableString *mstring = [NSMutableString stringWithString:string];
            NSRange wholeShebang = NSMakeRange(0, [string length]);

            [mstring replaceOccurrencesOfString: @"\n"
                     withString: @""
                     options: 0
                     range: wholeShebang];

            return [NSString stringWithString: mstring];

      (this can also be used for generic string manipulations, not just stripping out newlines).

      This technique takes half the time (at least) of split/join. But probably not enough to make
      an impact. In a simple test, split/join took 0.124 seconds to strip 36909 newlines in a 1.5
      meg textfile, and 0.071 seconds to do the same.

      Substring matching (NSString->General) [permalink]
      NSRange range = [[string name] rangeOfString: otherString options:

      Today's date as a string (NSString->General) [permalink]
      The general solution for converting a date to a string is NSDateFormatter. Sometimes you
      need to generate a date string in a particular format easily. For instance if you need
      "December 4, 2007", you can use:

      [[NSDate date] descriptionWithCalendarFormat: @"%B %e, %Y" timeZone: nil locale: nil]

      (Thanks to Mike Morton for this one)

      Put a string on the pasteboard (NSString->Random) [permalink]
      Here's a category for easily putting a string on the paste|clipboard:

      @implementation NSString (PasteboardGoodies)

      - (void) sendToPasteboard
              [[NSPasteboard generalPasteboard]
                  declareTypes: [NSArray arrayWithObject: NSStringPboardType]
              [[NSPasteboard generalPasteboard]
                  setString: self
                  forType: NSStringPboardType];
      } // sendToPasteboard

      @end // PasteboardGoodies

      Thanks to Dan Jalkut for this tip.

      Getting a document's window (NSDocument->General) [permalink]
      For 10.3 and later systems, use -windowForSheet (which doesn't tell you the window
      associated with a particular sheet, but instead returns the window to be used for showing
      sheets, which is usually what you want when talking about the document's window - Thanks
      to Peter Hosey for this one).

      For folks stuck in 10.2 land, or who want to do it themselves, there's always this:

      - (NSWindow *) window
          NSArray *windowControllers;
          windowControllers = [self windowControllers];

            NSWindowController *controller;
            controller = [windowControllers objectAtIndex: 0];

            NSWindow *window;
            window = [controller window];

            return (window);

      } // window

      Keeping backup files of documents (NSDocument->General)            [permalink]
      override NSDocument's keepBackupFile:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 33 of 57
All The Quickies                                                                                      11/20/08 9:07 AM

      override NSDocument's keepBackupFile:

      - (BOOL) keepBackupFile
          return (YES);
      } // keepBackupFile

      This will do the tilde thing to the older version of the file.

      Mapping a window to its document (NSDocument->General)           [permalink]

             NSDocumentController *documentController;
             documentController = [NSDocumentController sharedDocumentController];

             BWBorkStitchDocument *noteDocument;
             noteDocument = [documentController documentForWindow: noteWindow];

      Storing window position in the document (NSDocument->General) [permalink]
      If you want to store the window position in your document, you'll need to store and restore
      the [window frame] of the window in question. (That's left as an exercise to the reader,
      based on how you're storing your document contents.) When restoring the window location,
      you have to turn of NSWindowController's cascading, otherwise it'll honor your width and
      height, but not your origin. In your document's windowControllerDidLoadNib method,
      you'll need:

             [[self windowController] setShouldCascadeWindows: NO];

             NSWindow *window;
             window = [self window];
             [window setFrame: loadedWindowBounds display: YES];

      Using a custom title for NSWindowController windows (NSDocument->NSWindow)
      When using utility windows in a document-based app, NSWindowController is handy for
      handling a lot of the grungy details. When using a shared window (like an inspector window),
      you want its title to reflect that of the document. Override
      windowTitleForDocumentDisplayName to set the title. In this case, it becomes of the form
      "Overview of Untitled 2":

      - (NSString *) windowTitleForDocumentDisplayName: (NSString *) displayName
          NSString *string;
          string = [NSString stringWithFormat: @"Overview of %@", displayName];

             return (string);

      } // windowTitleForDocumentDisplayName

      Window Position Autosave for NSWindowController- owned inspectors (NSDocument-
      >NSWindow) [permalink]
      It's nice to autosave the position of inspector windows so that they come backup where the
      user put them. Unfortunately, NSWindowController wipes out the autosave name that's set in
      Interface Builder. You have to set it in code in your window controller subclass. The
      windowDidLoad method (which is used instead of awakeFromNib) is a handy place:

      - (void) windowDidLoad
          [super windowDidLoad];

             [self setShouldCascadeWindows: NO];
             [self setWindowFrameAutosaveName: @"pannerWindow"];

          // and any other windowDidLoad work to be done
      } // windowDidLoad

      Enabling and Disabling menu items (NSMenu->General) [permalink]
      Under most circumstances, it happens automatically: a menu item will be disabled if there is
      no object in the responder chain that handles the menu's action. If you want to override this
      behavior or extend it further, override validateMenuItem: and do something like this:

      - (BOOL) validateMenuItem: (id <NSMenuItem>) menuItem
          BOOL result = YES;

             if ([menuItem action] == @selector(deleteNote:)) {
                 if ([notes count] == 1) {
                     result = NO; // can't delete the last note

             } else if ([menuItem action] == @selector(gotoNote:)) {
                 if ([notes count] == 1) {
                     result = NO; // can't go to a different not if only one

             return (result);

      } // validateMenuItem

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                   Page 34 of 57
All The Quickies                                                                                                    11/20/08 9:07 AM

      Running code before a menu action is sent (NSMenu->General) [permalink]
      The NSMenuWillSendActionNotification is posted to the notification center before
      the action is invoked.

      Cheap profiling (Unix API->General) [permalink]
      You can use gettimeofday() to get sub-second granularity for timing:

      #include <sys/time.h>
      struct timeval start, end;
      gettimeofday (&start, NULL);

      ... the code you're timing

      gettimeofday (&end, NULL);
      double fstart, fend;
      fstart = (start.tv_sec * 1000000.0 + start.tv_usec) / 1000000.0;
      fend = (end.tv_sec * 1000000.0 + end.tv_usec) / 1000000.0;
      NSLog (@"it took %f seconds", fend - fstart);

      Making a timestamp with strftime (Unix API->General)          [permalink]

            time_t now;
            now = time(NULL);

            struct tm *tm;
            tm = localtime (&now);

            char timestamp[200];
            strftime (timestamp, 200, "%m/%d/%Y-%H:%M", tm);

      Handling double- clicks in a browser (NSBrowser->General)          [permalink]

      - (void) awakeFromNib
          [browser setTarget: self];
          [browser setDoubleAction: @selector(browserDoubleClick:)];
      } // awakeFromNib


      - (IBAction) browserDoubleClick: (id) sender
          int column = [browser selectedColumn];
          int row = [browser selectedRowInColumn: column];

            // then dig into your data structure with the row and column

      } // browserDoubleClick

      Moving a file to a tilde file (NSFIleManager->General)     [permalink]

            NSString *filename = @"/my/original/file/name";
            NSString *tildeFilename;
            tildeFilename = [NSString stringWithFormat: @"%@~", filename];

            // remove it first, otherwise the move will fail
            [defaultManager removeFileAtPath: tildeFilename
                            handler: nil];

            // now rename the file
            [defaultManager movePath: filename
                            toPath: tildeFilename
                            handler: nil];

      If you want to stick the tidle before the file extension (so the finder could open
      ook~.tiff), try this:

                   NSString *pathExtension = [filename pathExtension];
                   if (!pathExtension) {
                            tildeFilename = [filename stringByAppendingString: @"~"];
                   } else {
                            tildeFilename = [NSString stringWithFormat: @"%@~.%@", [filename stringByDeletingPathExtension], pathExtens

      (Thanks to Peter Hosey for this one)

      Removing a file (NSFIleManager->General)     [permalink]

            NSFileManager *defaultManager;
            defaultManager = [NSFileManager defaultManager];

            [defaultManager removeFileAtPath: tildeFilename
                            handler: nil];

      The handler is an object that will be sent message, like
      fileManager:shouldProceedAfterError: if something goes wrong during the removal.

      Saving an NSData to a file (NSFIleManager->General)        [permalink]

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                                 Page 35 of 57
All The Quickies                                                                                    11/20/08 9:07 AM

            NSString *filename = @"/this/is/my/file/name";
            NSData *data = // get NSData from somewhere, like NSPropertyListSerialization

          [data writeToFile: filename            atomically: NO];

      Reading property lists from XML (XML->General) [permalink]
      This will read property lists in XML (or any of the other property list formats:)

            NSData *data = // get NSData from somewhere, like NSFileManager
            if (data) {
                myRootObject = [NSPropertyListSerialization
                                   propertyListFromData: data
                                   mutabilityOption: NSPropertyListMutableContainers
                                   format: nil
                                   errorDescription: nil];

      For the mutability options of the resulting object, you can also use
      NSPropertyListImmutable and NSPropertyListMutableContainersAndLeaves

      Saving property lists as XML (XML->General) [permalink]
      You can save any of the "property list" classes (NSDictionary, NSArray,NSNumber,
      NSString, NSData) as XML like this:

            NSData *data;
            data = [NSPropertyListSerialization
                       dataFromPropertyList: notes
                       format: NSPropertyListXMLFormat_v1_0
                       errorDescription: nil];

      Then write out the data using NSFileManager, or whatever other mechanism you wish.

      Archiving a document using keyed archiving (NSCoder->General) [permalink]
      This uses the new Tiger NSDocument load/store. For real code you'll want to handle errors
      and create an appropriate NSError object. This also saves the document in an XML format.

      - (NSData *) dataOfType: (NSString *) typeName
                        error: (NSError **) error
          *error = nil;

            NSMutableData *data = [[NSMutableData alloc] init];

            NSKeyedArchiver *archiver;
            archiver = [[NSKeyedArchiver alloc]
                           initForWritingWithMutableData: data];
            [archiver setOutputFormat: NSPropertyListXMLFormat_v1_0];

            [archiver encodeObject: stitches forKey: @"stitches"];
            // and archive other stuff you want

            [archiver finishEncoding];

            return ([data autorelease]);

      } // dataOfType

      - (BOOL) readFromData: (NSData *) data
                    ofType: (NSString *) typeName
                     error: (NSError **) error
          *error = nil;

            NSKeyedUnarchiver *archiver;
            archiver = [[NSKeyedUnarchiver alloc]
                           initForReadingWithData: data];

            [stitches release];

            stitches = [archiver decodeObjectForKey: @"stitches"];
            // decode other stuff of interest

            [stitches retain];

            return (YES);

      } // readFromData

      Decoding one class as another (NSCoder->General) [permalink]
      If you change the name of a class, and then try to use NSUnarchiver to expand an archived
      stream, you'll get an error like this (in this case "BWRawPath" was renamed to "BWSymbol"):

      StitchEdit[3522] *** class error for 'BWRawPath': class not loaded

      In a convenient place (like in the +load method of your class), use NSUnarchiver's

      @implementation BWSymbol

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                 Page 36 of 57
All The Quickies                                                                                     11/20/08 9:07 AM

      + (void) load
          [NSUnarchiver decodeClassName: @"BWRawPath"
                        asClassName: @"BWSymbol"];

            // No need to [super load] - the superclass +load has already
            // been invoked automatically by the runtime.

      } // load

      Note that this won't help you if you're wanting to rename something that was added via
      encodeValueOfObjCType:. You'll have to write some code to unarchive your data using
      the old @encode(oldName) and then re-archive it as @encode(newName)

      (Thanks to Greg Miller for spotting an error in this quickie)

      Simple archiving (NSCoder->General) [permalink]
      To archive a single object (which can be something like an array or dictionary that contains
      other object), such as saving your document, do:

      - (NSData *) dataRepresentationOfType: (NSString *) aType
          NSData *data;
          data = [NSArchiver archivedDataWithRootObject: group];

            return (data);

      } // dataRepresentationOfType

      Simple unarchiving (NSCoder->General) [permalink]
      To unarchive a single object (which can be something like an array or dictionary that
      contains other object), such as loading your document, do:

      - (BOOL) loadDataRepresentation: (NSData *) data
                               ofType: (NSString *) aType
          // replace the moedl
          [group release];
          group = [NSUnarchiver unarchiveObjectWithData: data];
          [group retain];

            // make any associations to hook the new data into your document

            return (YES);

      } // loadDataRepresentation

      Supporting NSKeyedArchiving in your objects (NSCoder->General)           [permalink]
      They should conform to the NSCoding protocol.

      - (void) encodeWithCoder: (NSCoder *) coder
          [coder encodeInt: x forKey: @"x"];
          [coder encodeInt: y forKey: @"y"];
          [coder encodeObject: color1 forKey: @"color1"];
          [coder encodeObject: color2 forKey: @"color2"];
          [coder encodeInt: direction forKey: @"direction"];

      } // encodeWithCoder

      - (id) initWithCoder: (NSCoder *) coder
          if (self = [super init]) {
              x = [coder decodeIntForKey: @"x"];
              y = [coder decodeIntForKey: @"y"];
              color1 = [coder decodeObjectForKey: @"color1"];
              color2 = [coder decodeObjectForKey: @"color2"];
              direction = [coder decodeIntForKey: @"direction"];

            return (self);

      } // initWithCoder

      Supporting decoding (NSCoder->General)        [permalink]

      - (id) initWithCoder: (NSCoder *) aDecoder
          if (self = [super init]) {
              // or else [super initWithCoder: aDecoder] if your superclass
              // supports it. NSObject does not.

                   // decoding a C type
                   [aDecoder decodeValueOfObjCType: @encode(int)
                             at: &itemCount];

                   // decoding an array of C structs
                   if (items != NULL) {

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                  Page 37 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

                       free (items);
                   items = malloc (sizeof(BWRawPathItem) * itemCount);

                   int i;
                   for (i = 0; i < itemCount; i++) {
                       [aDecoder decodeValueOfObjCType: @encode(BWRawPathItem)
                                 at: &items[i]];

                   // decoding an object
                   name = [aDecoder decodeObject];
                   [name retain];

                   // any other random initializations that don't come from
                   // the encoder
                   fooby = -1;

            return (self);

      } // initWithCoder

      Supporting encoding (NSCoder->General)       [permalink]

      - (void) encodeWithCoder: (NSCoder *) aCoder
          // [super encodeWithCoder:] if you inherit from a class
          // that supports encoding. NSObject does not.

            // encoding a C type
            [aCoder encodeValueOfObjCType: @encode(int)
                    at: &itemCount];

            // encoding an array of C structs
            int i;
            for (i = 0; i < itemCount; i++) {
                [aCoder encodeValueOfObjCType: @encode(BWRawPathItem)
                        at: &items[i]];

            // encoding an object
            [aCoder encodeObject: name];

      } // encodeWithCoder

      Launching a task (NSTask->General) [permalink]
      Here are the basics to launch "ls -l -a -t" in the current directory, and then read the result
      into an NSString:

            NSTask *task;
            task = [[NSTask alloc] init];
            [task setLaunchPath: @"/bin/ls"];

            NSArray *arguments;
            arguments = [NSArray arrayWithObjects: @"-l", @"-a", @"-t", nil];
            [task setArguments: arguments];

            NSPipe *pipe;
            pipe = [NSPipe pipe];
            [task setStandardOutput: pipe];

            NSFileHandle *file;
            file = [pipe fileHandleForReading];

            [task launch];

            NSData *data;
            data = [file readDataToEndOfFile];

            NSString *string;
            string = [[NSString alloc] initWithData: data
                                       encoding: NSUTF8StringEncoding];
            NSLog (@"woop! got\n%@", string);

      Of course, you can use different NSFileHandle methods for different styles of reading, and
      you can make a pipe for standard input so you can feed data to the task.

      Performing complex pipelines. (NSTask->General) [permalink]
      You can create multiple NSTasks and a bunch of NSPipes and hook them together, or you
      can use the "sh -c" trick to feed a shell a command, and let it parse it and set up all the
      IPC. This pipeline cats /usr/share/dict/words, finds all the words with 'ham' in them,
      reverses them, and shows you the last 5.

            NSTask *task;
            task = [[NSTask alloc] init];
            [task setLaunchPath: @"/bin/sh"];

            NSArray *arguments;
            arguments = [NSArray arrayWithObjects: @"-c",

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 38 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

                                  @"cat /usr/share/dict/words | grep -i ham | rev | tail -5", nil];
             [task setArguments: arguments];
             // and then do all the other jazz for running an NSTask.

      One important note: , don't feed in arbitrary user data using this trick, since they could
      sneak in extra commands you probably don't want to execute.

      Stripping a string of all HTML tags via a perl script and NSTask (NSTask->General)
      Here is a little perl script called which removes everything that looks like an
      HTML / SGML / XML tag:


             while (<>) {
                 $_ =~ s/<[^>]*>//gs;
                 print $_;

      Be sure to chmod +x the script. Add it to your project, add a new "Copy Files" phase, and
      have it stick this script into the Executables directory.

      This method will take a string and feed it through the perl script:

      - (NSString *) stringStrippedOfTags: (NSString *) string
          NSBundle *bundle = [NSBundle mainBundle];
          NSString *stripperPath;
          stripperPath = [bundle pathForAuxiliaryExecutable: @""];

             NSTask *task = [[NSTask alloc] init];
             [task setLaunchPath: stripperPath];

             NSPipe *readPipe = [NSPipe pipe];
             NSFileHandle *readHandle = [readPipe fileHandleForReading];

             NSPipe *writePipe = [NSPipe pipe];
             NSFileHandle *writeHandle = [writePipe fileHandleForWriting];

             [task setStandardInput: writePipe];
             [task setStandardOutput: readPipe];

             [task launch];

             [writeHandle writeData: [string dataUsingEncoding: NSASCIIStringEncoding]];
             [writeHandle closeFile];

             NSMutableData *data = [[NSMutableData alloc] init];
             NSData *readData;

             while ((readData = [readHandle availableData])
                    && [readData length]) {
                 [data appendData: readData];

             NSString *strippedString;
             strippedString = [[NSString alloc]
                                  initWithData: data
                                  encoding: NSASCIIStringEncoding];

             [task release];
             [data release];
             [strippedString autorelease];

             return (strippedString);

      } // stringStrippedOfTags

      Using sockets with cocoa (Samples->General) [permalink]
      networkolizer.tar.gz is a very short sample that opens a socket connection (using the
      Berkeley sockets API), and then writes an HTTP request, and reads the response.

      Adding your own objects to the responder chain (NSObject->General) [permalink]
      For I project I was working on, I needed the editing tools (for a graphical editor) to be in the
      responder chain so they could react to menu items. Doing this was surprisingly easy.

      First step was to make the tools inherit from NSResponder:

      @interface BWTool : NSResponder
          // blah
      // ... more blah
      @end // BWTool

      Then, in the view class where the tool gets set, put the tool in the responder chain by
      setting its next responder to be the view's current next responder. If a different tool gets
      set, take the current tool's next responder and give it to the new tool. Otherwise the view
      gets its original next responder back:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 39 of 57
All The Quickies                                                                                 11/20/08 9:07 AM

      - (void) setTool: (BWTool *) newTool
          NSResponder *nextResponder;

            // this is the next element in the chain

            if (currentTool != nil) {
                nextResponder = [currentTool nextResponder];
            } else {
                nextResponder = [self nextResponder];

            // decide who gets to point to the next responder

            if (newTool != nil) {
                // stick the tool into the chain
                [self setNextResponder: newTool];
                [newTool setNextResponder: nextResponder];

            } else {
                // cut the tool out of the chain (if there was one)
                [self setNextResponder: nextResponder];

            [newTool retain];
            [currentTool release];

            currentTool = newTool;

      } // setDrawTool

      And now tools can have action methods, and menu items that enable and disable

      Apple's recommended retain/release technique (NSObject->General)         [permalink]
      This way if "get" performance is important:

      - (NSString*) title
          return (title);
      } // title

      - (void) setTitle: (NSString *) newTitle
          [title autorelease];
          title = [newTitle copy];
      } // setTitle

      For maximum safety in the face of threads, use this:

      - (NSString *) title
          return [[title retain] autorelease];
      } // title

      This puts title into the current thread's autorelease pool, so title is protected from
      being destroyed by someone else in another thread.

      - (void) setTitle: (NSString *) newTitle
          // use a mutex or NSLock to protect this
          if (title != newtitle) {
              [title release];
              title = [newTitle copy];
      } // setTitle

      By making a copy of the object, you're protected from another thread changing the value
      underneath you.

      Making a delegate (NSObject->General) [permalink]
      You've decided you want your class to have a delegate. Here's how you go about doing it:
        1. Make an id instance variable in your class, and make methods to set and get it:

            id   delegate;
            -(void) setDelegate: (id) del
                delegate = del; // you don't need to retain it
            } // setDelegate

            - (id) delegate
                return (delegate);
            } // delegate

         2. Make a category on NSObject so the compiler won't generate warnings, and also to
            document the delegate methods you support:

            @interface NSObject(BWStitchViewDelegate)

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                              Page 40 of 57
All The Quickies                                                                                        11/20/08 9:07 AM

            - (BOOL) shouldHandleStuff: (NSData *) data;

         3. Check to make sure your delegate understands the message before sending it.

            if ([delegate respondsToSelector: @selector(shouldHandleStuff:)]) {
                BOOL blah;
                blah = [delegate shouldHandleStuff: somedata];
                if (blah) ...

      Seeing the selectors objects ask you about (NSObject->General) [permalink]
      Sometimes it's handy to see when someone is asking your object what selectors it reponds
      to. Stick this in your class and you can see what folks are asking for:

      - (BOOL) respondsToSelector: (SEL) aSelector
          NSLog (@"%s", (char *) aSelector);
          return ([super respondsToSelector: aSelector]);

      } // respondsToSelector

      This takes advantage of an implementation detail where the SEL is actually a pointer to a C

      Should you retain the delegate in your objects? (NSObject->General) [permalink]
      If you're creating an object, and you provide a delegate feature, should you retain the
      delegate? Nope! These objects are peers, not an owner/owned, or parent/child relationship.
      If you free your object, you shouldn't need to worry about memory management of your
      delegate. Likewise, if someone releases the delegate object, they should clean up after
      themselves and tell you to have a nil delegate.

      Sorting with Selectors (NSObject->General) [permalink]
      You can sort mutable arrays by providing a selector that is invoked on each of the elements
      of the array. I always get confused about NSOrderedAscending / NSOrderedDescending (I
      think they're actually backwards, but that's just me). Here it is in a nutcase: Given this sort

            [themStitches sortUsingSelector: @selector(compareByRowLocation:)];

      And this selector on the BWCrossStitch class:

         - (NSComparisonResult) compareByRowLocation: (BWCrossStitch *) thing2;

      Figure out which is lesser or greater, and return one of these. Note that self is the object's
      logical value, not the actual value of the self pointer.
            NSOrderedAsending if self < thing2
            NSOrderedDescending if self > thing2
            NSOrderedSame if self == thing2

      My color well has a little triangle on it ? (NSColorWell->General) [permalink]
      If your color well has a little triangle in the corner after you set the color programatically,
      that probably means the NSColor you used was created in Device space (e.g.
      colorWithDeviceRed:green:blue:alpha:) If you use a Calibrated color
      (colorWithCalibratedRed:green:blue:alpha:), the triangle goes away.

      Posting notifications. (Notifications->General)     [permalink]
      In the header file:

      extern NSString *BWStitchGroup_VisualAttributeChangeNotification;

      In the .m file:

      NSString *BWStitchGroup_VisualAttributeChangeNotification
          = @"BWStitchGroup Visual Attribute Change Notification";

      NSNotificationCenter *center;
      center = [NSNotificationCenter defaultCenter];

      [center postNotificationName:
              object: self];

      Receiving notifications (Notifications->General)      [permalink]

      NSNotificationCenter *center;
      center = [NSNotificationCenter defaultCenter];

      [center addObserver: self
              selector: @selector(groupVisualChange:)
              name: BWStitchGroup_VisualAttributeChangeNotification
              object: group];

      Where the selector looks like this:

      - (void) groupVisualChange: (NSNotification *) notification

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                     Page 41 of 57
All The Quickies                                                                             11/20/08 9:07 AM

          // do stuff with the notification
      } // groupVisualChange

      Watching all notifications (Notifications->General) [permalink]
      There's three notification centers - one for the app, one for the workspace, and the
      distributed notification center. Here's how to watch everything:

      #import <Cocoa/Cocoa.h>
      #import <stdio.h> // for printf()

      @interface NotificationSpy

      + (void) startSpying;
      + (void) stopSpying;

      @end // NotificationSpy

      // prevent us from adding ourselves multiple times

      static BOOL g_spying;

      @implementation NotificationSpy

      // turn on listening for all notifications.

      + (void) startSpying
          if (!g_spying) {
              NSNotificationCenter *center;

                   // first the default notification center, which is all
                   // notifications that just happen inside of our program

                   center = [NSNotificationCenter defaultCenter];

                   [center addObserver: self
                           selector: @selector(observeDefaultCenterStuff:)
                           name: nil
                           object: nil];

                   // then the NSWorkspace notification center, which tells us things
                   // like other applications launching, and the machine sleeping
                   // and waking

                   center = [[NSWorkspace sharedWorkspace]

                   [center addObserver: self
                           selector: @selector(observeWorkspaceStuff:)
                           name: nil
                           object: nil];

                   //   and lastly the distributed notification center. This is a
                   //   global (to the computer) notification center. You can find
                   //   out when a different program gets focus, or the sound or
                   //   screen brightness changes.

                   center = [NSDistributedNotificationCenter
                                notificationCenterForType: NSLocalNotificationCenterType];

                   [center addObserver: self
                           selector: @selector(observeDistributedStuff:)
                           name: nil
                           object: nil];

                   g_spying = YES;

      } // startSpying

      // remove us as observers

      + (void) stopSpying
          if (!g_spying) {
              NSNotificationCenter *center;

                   // take us off the default center for our app
                   center = [NSNotificationCenter defaultCenter];
                   [center removeObserver: self];

                   // and for the workspace
                   center = [[NSWorkspace sharedWorkspace]
                   [center removeObserver: self];

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                          Page 42 of 57
All The Quickies                                                                                           11/20/08 9:07 AM

                   // and finally off of the machine-wide center
                   center = [NSDistributedNotificationCenter
                                notificationCenterForType: NSLocalNotificationCenterType];
                   [center removeObserver: self];

                   g_spying = NO;

      } // stopSpying

      + (void) observeDefaultCenterStuff: (NSNotification *) notification
          // QuietLog can also be found in the quickies
          QuietLog (@"default: %@", [notification name]);
      } // observeDefaultCenterStuff

      + (void) observeDistributedStuff: (NSNotification *) notification
          QuietLog (@"distributed: %@", [notification name]);
      } // observeDistributedStuff

      + (void) observeWorkspaceStuff: (NSNotification *) notification
          QuietLog (@"workspace: %@", [notification name]);
      } // observeWorkspaceStuff

      @end // NotificationSpy

      Converting .snd resource to aiff (NSSound->General) [permalink]
      Get SoundApp PPC (a classic App). Choose File->Convert, set these attributes:
           Format : AIFF
           Encoding : PCM
           Rate : 44100 Hz
           Bits : 16 bits
      and save. Then you can load it and play it with NSSound

      Addendum: NSSound is based on Core Audio and QuickTime as of 10.3, so it may be able to
      play .snd resource files as-is. So give that a try if you don't need to support 10.2 or earlier.
      (Thanks to Peter Hosey for the clarification.)

      Today's date (NSDate->General)        [permalink]

      NSDate *today;
      today = [NSDate date];

      Adding AppleHelp (Xcode->General) [permalink]
        1. Create a "AppName Help" directory in your English.lproj.

         2. Add an index.html Put in these headers:

              <meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
              <title>AppName Help</title>
              <meta name="AppleTitle" content="AppName Help">
              <meta name="AppleIcon" content="AppName%20Help/images/icon-name.png">
              <meta name="AppleFont" content="Lucida Grande,Helvetica,Arial">
              <meta name="AppleSearchResultsFont" content="Lucida Grande,Geneva,Arial">
              <meta name="robots" content="noindex">

            Along with your actual help content.

         3. Drag the AppName Help directory into your XCode project. When Adding, make sure
            "Copy items into destination group's folder" is unchecked, and select "Create Folder
            References for any add folders". You wnat XCode to preserve your AppName Help

         4. Add these to your Info.plist:

            <string>AppName Help</string>
            <string>AppName Help</string>

         5. Build, run, and cross your fingers. If is already running, you may want to exit

      Adding credits to your about box (Xcode->General) [permalink]
      If you have a file called "Credits.html" or "Credits.rtf", the contents of that file will be added
      to your about box. If your project doesn't have one already, you can use Xcode to add an
      empty file and put it in your English.lproj folder. Make sure you add it to your project.

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                        Page 43 of 57
All The Quickies                                                                                        11/20/08 9:07 AM

      empty file and put it in your English.lproj folder. Make sure you add it to your project.

      Apple - Generic Versioning (Xcode->General) [permalink]
      You can use agvtool do to apple-style generic versioning, which has two version numbers -
      one's a float that's monotonically increasing, and the other is a "marketing" version, that
      can be things like "1.0.4b34". Courtesy of Chris Hanson from a mailing list posting:

      Set your Versioning System (VERSIONING_SYSTEM) to "apple-generic".

      Set your Current Project Version (CURRENT_PROJECT_VERSION) to some floating point value
      that you'll increment every build. You could just start at 1, unless you already have builds
      out there with other numbers.

      This will generate and build a source file automatically that defines two globals whenever
      you build your project. One is a double corresponding to CURRENT_PROJECT_VERSION, the
      other is a string. The file is a derived source file; it won't be added to your project, but it
      will be built with it.

      If you're building a framework, there are other build settings you'll probably want to set as
      well, such as Current Version (DYLIB_CURRENT_VERSION), Compatibility Version

      To update the version number, you can use agvtool next-version or agvtool new-version.

      Changing extension for a bundle (Xcode->General) [permalink]
      The default extension for a CocoaBundle is ".bundle". To change it to something else, use
      the WrapperExtension target property. Select the top-most item in the groups and files list,
      show the Info panel, choose Styles, and look for Wrapper Extension. Set that to what you
      want (such as "service"). Don't include the dot.

      Changing the default Project Builder projects (Xcode->General) [permalink]
      Don't like something about the default project that Xcode gives you? Look in
      /Library/Application Support/Apple/Developer Tools/Project Templates/
      and edit the projects there.

      (For Project Builder, go to /Developer/ProjectBuilder Extras/Project Templates/
      and edit the projects there. The changes will take effect next time you create a new

      Command- line building from xcode (Xcode->General) [permalink]
      xcodebuild is the pbxbuild equivalent. To get a development build, you'll need to specify
      the style:
      % xcodebuild -buildstyle Development

      Debugging unit tests from the command - line (Xcode->General)            [permalink]
      First, find the .octest file of interest:

      % find . -name "*.octest" -print

      Then gdb Tools/otest:

      % gdb /Developer/Tools/otest

      Then run it with the name of the bundle:

      (gdb) run ./build/Debug/Tests.octest

      Enabling "control reaches end of non- void function" (Xcode->General) [permalink]
      One nice gcc warning that's not enabled by default is one that complains if you exit from a
      function (by falling off the end) without returning anything. This is an easy error to make,
      and can be hard to track down (especially if you do it in an objective-C init method). To
      enable this warning, add "-Wreturn-type" to the "Other C Flags" setting in your favorite
      build style.

      Fixing undefined symbols when building plugins (Xcode->General) [permalink]
      If you have a plugin defined as a "Cocoa Bundle" target in Xcode, and your plug-in inherits
      from a class that's defined in the application, you may get a build error like:

      ld: Undefined symbols:

      You can fix this by adding -undefined dynamic_lookup to the "Other Linker Flags" of
      the Build Tab of the Target Settings for your plugin (whew!). You also need to make sure
      that the "Mac OS X Deployment Target" is 10.2 or later before using this flag.

      How do I add a new folder to my Files view ? (Xcode->General) [permalink]
      Select the folder you want the new folder to be a child of. Select Project->New Group.
      Give it a name. Note that the hierarchy of files in Xcode is a fantasy of the project, and
      doesn't necessarily reflect what's actually in the file system.

      Mysterious duplicated symbols (Xcode->General) [permalink]
      This killed a big chunk of time, so I figured I better record it here. While building a C++
      shared library, I was getting errors like:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                     Page 44 of 57
All The Quickies                                                                                               11/20/08 9:07 AM

      ld: multiple definitions of symbol __ZN13CaptureWidgetD2Ev
      normal/ppc/capturewidget-F17F43C0.o definition of
      __ZN13CaptureWidgetD2Ev in section (__TEXT,__text)
      normal/ppc/capturewidget-F17F43C0.o definition of
      __ZN13CaptureWidgetD2Ev in section (__TEXT,__text)

      This is especially annoying, because the same object file is listed as having a duplicated
      symbol. If you take out the file from being compiled, you get undefined symbols for that
      particular source file, and if you put it back in, you get duplicated symbols.

      Turn out the problem is that Xcode (somehow) added the C++ file to the "Build Sources"
      phase of the target. It happily generated two identical object files, and proceded to link
      them (hence the error), but doesn't get the reporting information correct (hence saying that
      both symbols come from the same file)

      Open documentation for a symbol (Xcode->General) [permalink]
      Say you have "NSFishmonger" in your code, and you want to see the header. Option-double-
      click on NSFishmonger and it will bring up the header file.

      Open header for a symbol (Xcode->General) [permalink]
      Say you have "NSColor" in your code, and you want to see the header. Command-double-
      click on NSColor and it will bring up the header file.

      Renaming "MyDocument" (Xcode->General) [permalink]
      I find the default name "MyDocument" that Xcode uses for new document-based Cocoa
      apps to be annoying, sounding more appropriate for Fisher-Price toys than professional
      software. Renaming all of the moving pieces in Xcode can be a bit daunting, and I don't want
      to edit the project template, since those tend to get revised as time goes on. This is what I
         1. make the new project
         2. replace MyDocument with the newDocument name (BWGraphDocument here):
             perl -pi -e 's/MyDocument/BWGraphDocument/g' *.[hm] *.xcodeproj/*
         3. rename the document files:
             mv MyDocument.h BWGraphDocument.h
             mv MyDocument.m BWGraphDocument.m
         4. rename the nib file:
             mv MyDocument.nib BWGraphDocument.nib
         5. open the nib file, drag in your document header and change the
             class of the File's Owner to the new class. Delete the MyDocument

      Runing a unit test in ppc mode (Xcode->General) [permalink]
      Say your xcode project happily runs unit tests in i386 mode. You're about to land something
      that does byte-swapping, and you want to make sure it's sane in PPC mode, and you
      haven't turned on your G5 in months. You can do this command-line styles on your ICBM
      (assuming your project doesn't already do ppc and i386 unit tests). Build your test, and use
      translate to run the powerPC side of the world:

      % xcodebuild -configuration Release -target "Test All" -project Tests.xcodeproj NATIVE_ARCH="i386 ppc"

      % /usr/libexec/oah/translate /Developer/Tools/otest build/Release/Tests.octest

      Running a specific unit test from the command line (Xcode->General)                [permalink]

      % /Developer/Tools/otest -SenTest             ClassName ./build/Debug/TheUnitTest.octest

      Running a unit- test from the command line (Xcode->General)          [permalink]

      % /Developer/Tools/otest path/to/build/Unittest/TheUnit Test.octest

      Setting compiler flags on a per- file basis (Xcode->General) [permalink]
      Sometimes you need to set compiler flags on a per-file basis, like you need to suppress a
      warning in one place or set a one-off #define, but not for the entire project. You can set
      these flags in the build tab of the Get Info window of the source file in the target's
      compile sources build phase If you get info on the source file in other places in Xcode,
      there's no build tab, and you're left with that "Am I crazy? I know I've seen that setting
      somewhere before, but where is it? I better go back to listening to Finnish polkas 24/7 and
      give up this software thing" kind of feeling.

      Toggle between the source file and its header file. (Xcode->General)               [permalink]
      comand-option-up arrow

      Treat warnings as errors (Xcode->General) [permalink]
      In Xcode, there's a handy "Treat Warnings as Errors" checkbox. I usually use the search
      dealie with "werr" to find the setting.

      (In Project Builder, open the Targets tab, double-click the target, go to the "Build Settings"
      tab, scroll down to Build Settings, look for WARNING_CFLAGS. Edit that, and add -Werror
      to what's already there.)

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                            Page 45 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

      Turning off ZeroLink in all of the project templates (Xcode->General) [permalink]
      I loathe ZeroLink. It causes more problems than it fixes. The Xcode guys must love it dearly.
      The new .xcconfig files in Xcode 2.1 won't let you turn it off, rendering those files useless
      to me. The Official Apple suggestion is to edit all of your project templates (?). Here is a
      quick script that'll churn through all of the project templates (and also your own projects)
      and turn off ZeroLink.

      % cd '/Library/Application Support/Apple/Developer Tools/Project Templates'
      % find . -name "*.pbxproj" -exec perl -pi -e "s/ZERO_LINK = YES/ZERO_LINK = NO/g" {} \; -print

      Using Objective C++ (Xcode->General) [permalink]
      name your source file blah.M (upper case M), or name your source file (two lower
      case Ms). It's best to use .mm because of the case-insensitive (yet case-preserving) nature
      of HFS+

      XCode's default projects (Xcode->General) [permalink]
      XCode looks in /Library/Application Support/Apple/Developer Tools/Project
      Templates/ for the templates for its projects. You can put your own project templates
      here, and tweak the existing templates (for instance, Xcode 1.1's Cocoa projects have a
      compiler warning in main.m, which is really annoying for those of use who treat warnings as
      errors. You can go into /Library/Application Support/Apple/Developer
      Tools/Project Templates/Application/Cocoa Application/ and fix that warning
      if you wish.

      Blanket Disabling of ZeroLink (Xcode->Hacks)       [permalink]
      (see also ZeroLink Must Die.

      This find will grovel around project files and turn off ZeroLink. You can start at the path here
      to turn it off in all of your Xcode templates, and you can also point the find at your own
      XCode projects. Make backups first if you're feeling squeamish or your stuff isn't under
      version control.

      % cd '/Library/Application Support/Apple/Developer Tools/Project Templates'
      % find . -name "*.pbxproj" -exec perl -pi -e "s/ZERO_LINK = YES/ZERO_LINK = NO/g" {} \; -print

      Non - chunky high - DPI image drawing (NSImage->General) [permalink]
      If you load NSImages from random files and draw them larger than they say they are,
      sometimes you get a really chunky, pixellated display for images that have a high DPI rather
      than a smooth interpolation (or even using all those extra pixels due to the high DPI). This is
      because (I think) that the image says that it's 100x100, even though you have 1000x1000
      pixels available, and Cocoa decides to scale up only 100x100 pixels.

      One way to hack around it is to tell the image to use the pixel size of the underlying image

            NSImage *image;
            image = [[NSImage alloc] initWithContentsOfFile: path];

            NSBitmapImageRep *rep = [[image representations] objectAtIndex: 0];
            // If you think you might get something other than a bitmap image representation,
            // check for it here.

            NSSize size = NSMakeSize ([rep pixelsWide], [rep pixelsHigh]);
            [image setSize: size];

      Saving an image as a file (NSImage->General)       [permalink]
      To save an imageRep as a PNG file:

      NSBitmapImageRep *bits = ...; // get a rep from your image, or grab from a view

      NSData *data;
      data = [bits representationUsingType: NSPNGFileType
                    properties: nil];
      [data writeToFile: @"/path/to/wherever/test.png"
            atomically: NO];

      There are also TIFF, BMP, GIF, JPEG file types in addition to PNG.

      Binding to your AppController (Bindings->General) [permalink]
      If you have an AppController object in your nib file, and it's not File's Owner, but you want
      to use bindings with it, you can use an NSObjectController :
         1. Make an IBOutlet in your controller to point to the NSObjectController
         2. Drag an NSObjectController into the nib
         3. Add the names of the properties you're going to be binding with
         4. in AppController's awakeFromNib method, do [objController setContent:
      By setting the content value in awakeFromNib helps prevent a retain cycle which can lead
      to memory leaks.

      Changing the "Not Applicable" text in tableviews (Bindings->General) [permalink]
      Sometimes you want to bind a tableview column to objects that might not support that
      particular binding (like having an uber-overview tableview for core data entities that don't all
      share the same attributes). If your column has a numeric formatter, IB won't let you specify
      a string for the "not applicable" value, so you end up with a really ugly tableview covered in
      "Not Applicable"s

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 46 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

      "Not Applicable"s

      Put this in a convenient place:

      + (void) initialize
          [NSTextFieldCell setDefaultPlaceholder: @""
                                     forMarker: NSNotApplicableMarker
                                   withBinding: NSValueBinding];

      } // initialize

      Handling KVO with arrays (Bindings->General) [permalink]
      When you insert or remove objects in a KVO compliant manner, your observer is informed of
      the specifics of the change via the change dictionary:

      - (void) observeValueForKeyPath:           (NSString *) keyPath
                             ofObject:           (id) object
                               change:           (NSDictionary *) change
                              context:           (void *) context

      The NSKeyValueChangeKindKey key in the dictionary tells you if the change was an
      insertion (NSKeyValueMinusSetMutation) or a deletion

      If it is an insertion, the NSKeyValueChangeIndexesKey is an index set that contains the
      index of the inserted object. You can query the collection for the object at that index to get
      the new object.

      if it a deletion, the NSKeyValueChangeIndexesKey tells you the index where the object
      was deleted from, and the NSKeyValueChangeOldKey contains an NSArray of objects
      which were removed, in case you want to hang on to it, or use it to clean out some of your
      data structures.

      Handling unknown keys with KVC (Bindings->General)         [permalink]
      Override valueForUndefinedKey::

      - (id) valueForUndefinedKey: (NSString *) key
          id value;
          value = [self lookUpValueUsingSomeOtherMechanism: key];

            if (value == nil) {
                value = [super valueForUndefinedKey: key];

            return (value);

      } // valueForUndefinedKey

      Some handy uses for this is using the user defaults for storing values (you can use the key
      directly to [NSUserDefaults stringForKey:], or use it to query the contents of an

      The counterpart for this is

      - (void) setValue: (id) value forUndefinedKey: (NSString *) key, which
      you can use to stash stuff into user prefs or a dictionary.

      Hooking up a search box to your array controller (Bindings->General) [permalink]
      Tiger supposedly does this for us. If you're having to support Panther as well, here's a way
      to have a search box filter the contents managed by an NSArrayController.

      In the header file

      #import <Cocoa/Cocoa.h>

      @interface BWSearchArrayController : NSArrayController
          NSString *searchString;

      - (IBAction) search: (id) sender;

      @end // BWSearchArrayController

      and then in the implementation:

      // returns an array containing the content of the objects arranged
      // with the user's critera entered into the search box thingie

      - (NSArray *) arrangeObjects: (NSArray *) objects
          // result of the filtering
          NSArray *returnObjects = objects;

            // if there is a search string, use it to compare with the
            // search field string

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 47 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

            if (searchString != nil) {

                   // where to store the filtered
                   NSMutableArray *filteredObjects;
                   filteredObjects = [NSMutableArray arrayWithCapacity: [objects count]];

                   // walk the enumerator
                   NSEnumerator *enumerator = [objects objectEnumerator];

                   id item; // actully BWFileEntries
                   while (item = [enumerator nextObject]) {

                       // get the filename from the entry
                       NSString *filename;
                       filename = [item valueForKeyPath: @"fileName"];

                       // see if the file name matches the search string
                       NSRange range;
                       range = [filename rangeOfString: searchString
                                         options: NSCaseInsensitiveSearch];

                       // found the search string in the file name, add it to
                       // the result set
                       if (range.location != NSNotFound) {
                           [filteredObjects addObject: item];

                   returnObjects = filteredObjects;

            // have the superclass arrange them too, to pick up NSTableView sorting
            return ([super arrangeObjects:returnObjects]);

      } // arrangeObjects

      and then to set the search string:

      - (void) setSearchString: (NSString *) string
          [searchString release];

            if ([string length] == 0) {
                searchString = nil;
            } else {
                searchString = [string copy];

      } // setSearchString

      - (void) search: (id) sender
          [self setSearchString: [sender stringValue]];
          [self rearrangeObjects];

      } // search

      KVO Array controller gotcha (Bindings->General) [permalink]
      If you're doing KVO and don't override
      observeValueForKeyPath:ofObject:change:context:, (or you do override it but
      don't handle your callbacks) you'll generally get an exception. This trains you to do it right
      and never call super for the callbacks you're handling, or you'll get an exception.

      Except if you've added KVO to a subclass of NSArrayController (and possibly all
      controller types), and don't call super's
      observeValueForKeyPath:ofObject:change:context:, bindings won't work at all,
      with no warning/notice/nothing. (Courtesy of Duncan Wilcox)

      Manually creating a binding (Bindings->General)      [permalink]

      [imageView bind: @"valuePath"
                 toObject: imagesController
                 withKeyPath: @"selection.fullPath"
                 options: nil];

      In Interface Builder, "Bind To" corresponds to imagesController, "Controller Key" would
      be selection, and "Model Key Path would be fullPath.


            [imageView unbind: @"valuePath"];

      to remove a binding.

      Minimal KVC accessors for arrays (Bindings->General) [permalink]
      For an attribute named "layers", here are the KVC accessors to write to let observers react
      to object addition and removal:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 48 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

      - (NSArray *) layers
          return (layers);
      } // layers

      - (void) insertObject: (id) obj
            inLayersAtIndex: (unsigned) index
          [layers insertObject: obj atIndex: index];
      } // insertObjectInLayers

      - (void) removeObjectFromLayersAtIndex: (unsigned) index
          [layers removeObjectAtIndex: index];
      } // removeObjectFromLayersAtIndex

      Monitoring one array from two controllers (Bindings->General) [permalink]
      If you're wanting to use two NSArrayControllers to monitor one NSMutableArray, you'll need
      to use each of the controller's contentArray binding. Just using the content outlet (or
      setContent: call), you'll only get arrangedObjects updates from one controller. (thanks to
      Duncan Wilcox for this one)

      NSSearchField filtering for an NSArrayController (Bindings->General) [permalink]
      In Tigger, NSSearchField can now automagically filter an array via IB magic.

      In Interface Builder, drag over the NSSearchField, and bind the predicate like this:

            Bind To: your array controller
            Controller Key: filterPredicate
            Predicate Format: what contains[c] $value (assuming the attribute you're
            filtering is called what)
      If you're wanting to be able to filter on multiple attributes, make additional predicate
      bindings. Doing the CoreData option-drag of an entity into IB is really handy - take a peek at
      how it configures the search field for filtering multiple columns.

      Observing using KVO (Bindings->General)      [permalink]
      Register an observer with something like:

            [searchArrayController addObserver: self
                                   forKeyPath: @"selectionIndexes"
                                   options: NSKeyValueObservingOptionNew
                                   context: NULL];

      This makes self an observer of the searchArrayController. We'll get notified when the
      selectionIndexes value changes, and we'll be notified with the new value.

      When the notification happens, this method (invoked against the self used earlier) is

      - (void) observeValueForKeyPath:            (NSString *) keyPath
                             ofObject:            (id) object
                               change:            (NSDictionary *) change
                              context:            (void *) context
      } // observeValueForKeyPath

      and you can poke around the arguments to see wha'happened.

      Registering default user defaults (Bindings->General) [permalink]
      Here is one way to register the "factory settings" for your user defaults (preferences /
      configurations). You will pick up these values automagically via bindings to the Shared

      - (void) setDefaultPrefs
          NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

            [dictionary setObject: NSLocalizedString(@"BorkDown", nil)
                        forKey: @"menuTitle"];

            [dictionary setObject: NSLocalizedString(@"Time has run out.", nil)
                        forKey: @"alertWindowText"];

            // and any other preferences you might have

            [[NSUserDefaults standardUserDefaults]
                registerDefaults: dictionary];

      } // setDefaultPrefs

      Using KVO for whole- object observation (Bindings->General) [permalink]
      I've got an object that has a bunch of individual attributes that are controlled by an
      inspector, and another object (a view that holds that object) which needs to redraw when
      something changes in the object, but it doesn't care which individual attribute it is. Rather
      than having the view observe each of the individual attributes, KVO provides a way to
      automatically trigger another observation when any dependent attribute changes.

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 49 of 57
All The Quickies                                                                                       11/20/08 9:07 AM

      automatically trigger another observation when any dependent attribute changes.

      First, in the +initialize for the class that's going to be observed:

      + (void) initialize
          NSArray *keys;
          keys = [NSArray arrayWithObjects: @"showMajorLines", @"minorWeight",
                          @"minorColor", @"minorWeightIndex", @"minorColorIndex",
                          @"majorWeightIndex", @"majorColorIndex", nil];

                setKeys: keys
                triggerChangeNotificationsForDependentKey: @"gridAttributeChange"];

      } // initialize

      So now when "showMajorLines" changes, "gridAttributeChange" will also be observed. KVO
      requires there actually must exist a gridAttributeChange method (or ivar I presume) before
      it'll do the notification to observing objects, so there needs to be a do-nothing method:

      - (BOOL) gridAttributeChange
          return (YES);
      } // gridAttributeChange

      So now the view can do this:

      - (void) setGridAttributes: (BWGridAttributes *) a
          [attributes removeObserver: self
                      forKeyPath: @"gridAttributeChange"];

            [a retain];
            [attributes release];
            attributes = a;

            [a addObserver: self
               forKeyPath: @"gridAttributeChange"
                options: NSKeyValueObservingOptionNew
                context: NULL];

      } // setGridAttributes

      And will get updated whenever an individual attribute changes.

      View with bindings (Bindings->General) [permalink]
      ThumbBorker has a custom view class that updates a selection rectangle when the user
      finished dragging the mouse. It uses setValue:forKeyPath: to stick the value back into
      the bound object.

      The bindings and path are ivars:

             id selectionRectBinding;
             NSString *selectionRectKeyPath;

      In bind:toObject:withKeyPath:options: hang on to the binding object and the key
      path and set up observing:

                   // hold on to the binding info
                   selectionRectBinding = observableObject;
                   selectionRectKeyPath = [observableKeyPath copy];

                   // connect KVO
                   [valuePathBinding addObserver: self
                                     forKeyPath: selectionRectKeyPath
                                     options: nil
                                     context: NULL];

                   // new binding, needs to redraw
                   [self setNeedsDisplay: YES];

      And in the mouseUp: handler, set the value back into the bound object:

             // figure out the selection rectangle
             NSRect selectionRect = [self normalizedSelectionRect];

             // wrap in a value and tell the bound object the new value

             NSValue *value;
             value = [NSValue valueWithRect: selectionRect];

             [selectionRectBinding setValue: value
                                   forKeyPath: selectionRectKeyPath];

      Fixing Bindings- related memory leak (Bindings->Hacks) [permalink]
      If you have bindings hooked up to File's Owner in some circumstances (like with an
      NSWindowController-based nib file), a retain cycle is created, and so the window controller
      will never get released (having an extra retain for each binding to File's Owner). An easy way
      to work around this is to;

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                    Page 50 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

            Add an NSObjectController (I call it "Fake FIle's Owner") to the nib file and the window
            controller class.
            Point the bindings to the controller rather than file's owner
            Hook up the window controller's outlet to point to the object controller
            [fakeFileOwner setContent: self]
      Then again, this all might be Wrong. jkp_ in #macdev points out that the setContent:self will
      retain self twice more, with no release in sight. The only wayd that would really work is if
      you provided a subclass of NSObjectController that released after it setContent: and also in
      _startObservingObject: That might be the cleanest solution - provide a custom proxy object
      that doesnt retain the filesOwner and bind to that....same thing, only you have to do the
      overrides. So this one's in limbo(e) for now. wheeee! He's come up with a hack to work
      around things:

      - (oneway void) release;
          // special case when count is 3, we are being retained twice by the object controller...
          if ( [self retainCount] == 3 )
              [super release];
              [filesOwnerProxy setContent:nil];

             [super release];

      Enabling buttons based on tableview selection (Bindings->NSTableView)            [permalink]
      Bind to your array controller selection, using @count.

      Reacting to TableView selection changes when using bindings (Bindings-
      >NSTableView) [permalink]
      You're using bindings to handle the tableview, but now you have some code that needs to
      do something when the selection changes (in my case I was disabling a sheet's OK button if
      the selection in two tableviews was the same). The way to track that change is to add
      yourself as an observer of the array controller that's driving the tableview, and then do the
      work in the observeValueForKeyPath: method. Register your observer like this:

             [searchArrayController addObserver: self
                                    forKeyPath: @"selectionIndexes"
                                    options: NSKeyValueObservingOptionNew
                                    context: NULL];

      So now self's observeValue method will get invoked when selectionIndexes changes in
      the array controller.

      Responding to a scrollview scrolling (NSScrollView->General) [permalink]
      If you need to react to a scrollview being scrolled by the user, first tell the contentView (the
      NSClipView) to post notifications when its bounds changes, and then register to receive an

             [[scrollView contentView] setPostsBoundsChangedNotifications: YES];

             NSNotificationCenter *center = [NSNotificationCenter defaultCenter] ;
             [center addObserver: self
                     selector: @selector(boundsDidChangeNotification:)
                     name: NSViewBoundsDidChangeNotification
                     object: [scrollView contentView]];

      - (void) boundsDidChangeNotification: (NSNotification *) notification
          [self setNeedsDisplay: YES];
          // or whatever work you need to do

      } // boundsDidChangeNotification

      Scrolling an NSScrollView programatically (NSScrollView->General) [permalink]
      Sometimes you need to scroll a scrollview outside of user control. You first have to tell the
      content view (Which is an NSClipView) to scroll to a point, and then tell the scrollview to
      adjust its scrollbar position:

             [[scrollView contentView] scrollToPoint: pointToScrollTo];
             [scrollView reflectScrolledClipView: [scrollView contentView]];

      Add new directory directly to repository (Subversion->General) [permalink]
      % svn mkdir -m "initial revision" file:///usr/local/svnroot/MilleBorks

      Adding new project to repository (1 project : 1 repository) (Subversion->General)
      The Subversion folks recommend that project have a branches, tag, and trunk directory, to
      make doing things like branches and tags easier. Importing this way will mean your repository
      will only have this one project.

      % mkdir DungeonBorkventure
      % cd DungeonBorkventure
      % mkdir branches tags trunk

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 51 of 57
All The Quickies                                                                                          11/20/08 9:07 AM

      #   put source files into trunk
      %   svn import . file:///usr/local/svnroot -m "initial checkin"
      %   cd ..
      %   rm -rf DungeonBorkventure # or move it aside
      %   svn checkout file:///usr/local/svnroot/trunk DungeonBorkventure
      %   cd DungeonBorkventure
      #   and get to work

      Adding new project to repository (multiple projects : 1 repository) (Subversion-
      >General) [permalink]
      To have multiple projects in one repository, you have to create directories in the repository
      first to hold the project, then import the code. Here is importing two projects, MilleBorks
      and DungeonBorkventure

      First, make the directories in the repository:

      % svn mkdir -m "initial revision" file:///usr/local/svnroot/DungeonBorkventure
      % svn mkdir -m "initial revision" file:///usr/local/svnroot/MilleBorks

      Then import the different code bases:

      %   cd /path/to/DungeonBorkventure
      %   svn import -m "initial revision" . file:///usr/local/svnroot/DungeonBorkventure
      %   cd /path/to/MilleBorks
      %   svn import -m "initial revision" . file:///usr/local/svnroot/MilleBorks

      Then checkout working copies of the projects:

      % cd /work/and/play/area
      % svn checkout file:///usr/local/svnroot/MilleBorks/trunk MilleBorks
      % svn checkout file:///usr/local/svnroot/DungeonBorkventure/trunk DungeonBorkventure

      Ignoring files (Subversion->General) [permalink]
      I don't want subversion to mess with some files, or to tell me about them when doing an
      svn status. Add this to your ~/.subversion/config file.

      global-ignores = build *.mode1 *.pbxuser *~.nib .DS_Store *~

      Now it won't bug me about the build directory the -per-user Xcode files, nib backup files,
      the #$&!! .DS_Store file that the Finder litters everywhere, and also don't bug me about
      emacs backup files.

      You can search for global-ignores in that file to see some info about the setting.

      Making a new FSFS repository (Subversion->General) [permalink]
      % svnadmin create --fs-type fsfs /usr/local/svnroot/

      Making a tag / branch (Subversion->General) [permalink]
      This will make a tag called "stable-1" of the current trunk revision:

      % svn copy file:///usr/local/svnroot/HackDie/trunk
                  -m "tag for HackDie internal stable release #1"

      Seeing what files will come down in the next update (Subversion->General) [permalink]
      To see if folks have committed changes that'll get brought down in the next update.

      % svn status --show-updates

      You can specify files and directories of interest.

      Showing all files that changed at a particular revision (Subversion->General)         [permalink]
      If you're inside of a working copy, you can do:

      % svn log -v -r 373
      r373 | markd | 2005-06-22 16:05:38 -0400 (Wed, 22 Jun 2005) | 1 line
      Changed paths:
         A /xyz/trunk/docs/bugreports/4158233-nsbrowser
         A /xyz/trunk/docs/bugreports/4158233-nsbrowser/browser-rows.png
         A /xyz/trunk/docs/bugreports/4158233-nsbrowser/browserdraw.tar.gz
         A /xyz/trunk/docs/bugreports/4158233-nsbrowser/bug.txt

      initial revision

      and you can look repository-wide too: % svn log -v -r 373

      Subversion over ssh (Subversion->General) [permalink]
      To access a repository that lives over ssh (vs http or file), use the svn+ssh protocol thingie
      in the commands, like
      % svn mkdir -m "initial revision"

      Changing a working tree's repository location (Subversion->Hacks) [permalink]
      Sometimes your subversion repository moves (like if you're using a private one and the
      machine changes addresses). Here's how to repoint a working tree to the new location
      (handy if there's outstanding changes that are a pain to move over to a fresh checkout)

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                       Page 52 of 57
All The Quickies                                                                                    11/20/08 9:07 AM

      (handy if there's outstanding changes that are a pain to move over to a fresh checkout)

      % svn switch --relocate

      Muchos thankos to Lucas Eckels for the tip.

      Custom Accessor Methods (scalar) (Core Data->General)        [permalink]
      Say there's a float ivar called radius

      - (float)    radius
          [self    willAccessValueForKey: @"radius"];
          float    f = radius;
          [self    didAccessvalueForKey: @"radius"];

          return (f);

      } // radius

      - (void) setRadius: (float) newRadius
          [self willChangeValueForKey: @"radius"];
          radius = newRadius;
          [self didChangeValueForKey: @"radius"];

      } // setRadius

      Custom accessor methods (objects) (Core Data->General) [permalink]
      Wrap the methods with will/did Access/Change ValueForKey:, and also use KVC to set
      primitive values:

      - (NSString *) name
          [self willAccessValueForKey: @"name"];
          NSString *string = [self primitiveValueForKey: @"name"];
          [self didAccessValueForKey: @"name"];
      } // name

      - (void) setName: (NSString *) x
          [self willChangeValueForKey: @"name"];
          [self setPrimitiveValue: x forKey: @"name"];
          [self didChangeValueForKey: @"name"];
      } // setName

      Inserting an object (Core Data->General) [permalink]
      Inserting a new object into a managed object context is a multi-stage process. This assumes
      that self has methods to get the managed object context and managed object model
      (Apple's CoreData Application template does)

            NSManagedObjectContext *moc = [self managedObjectContext];
            NSManagedObjectModel *mom = [self managedObjectModel];

            NSEntityDescription *entity;
            entity = [[mom entitiesByName] objectForKey: @"Condition"];

            NSString *className;
            className = [entity managedObjectClassName];

            NSManagedObject *obj;
            obj = [[NSClassFromString(className) alloc]
                      initWithEntity: entity
                      insertIntoManagedObjectContext: moc];

            [obj autorelease];

            [obj setValue: @"nook" forKey: @"name"];
            [obj setValue: [NSNumber numberWithInt: 23]              forKey: @"ranking"];

      Manipulating a to- many relationship (Core Data->General) [permalink]
      Use mutableSetValueForKey: This returns a proxy that mutates the relationship and
      does KVO notifications. Think of the name as "[NS]MutableSet" "valueForKey" rather than
      "mutableSetValue" "forKey", because it returns a mutable set that you manipulate

      NSMutableSet *employees;
      employees = [department mutableSetValueForKey: @"employees"];
      [employees addObject: newEmployee];
      [employees removeObject: sackedEmployee];

      Manually sorting results in a fetch request (Core Data->General) [permalink]
      I haven't figured out how to get the Xcode fetched query editor to sort. In the mean time,
      here's how to do it in code:

            NSSortDescriptor *sorter;
            sorter = [[NSSortDescriptor alloc]
                         initWithKey: @"when"
                         ascending: YES];

            [fetchRequest setSortDescriptors:

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                 Page 53 of 57
All The Quickies                                                                                          11/20/08 9:07 AM

                          [NSArray arrayWithObject: sortDescriptor]];

      Setting computed default value for a managed object (Core Data->General)              [permalink]
      Make a subclass of NSManagedObject and override awakeFromInsert:

      - (void) awakeFromInsert
          [super awakeFromInsert];

             NSDate *date = [NSDate date];

             [self setValue: date       forKey: @"when"];

      } // awakeFromInsert

      Sorting results (Core Data->General) [permalink]
      Want data to be sorted in tableviews and whatnot? You can set the "sortDescriptors"
      binding on an array controller. Write a method that returns the sort descriptors you want:

      - (void) setWhenSortDescriptors: (NSArray *) descriptors
      } // setWhenSortDescriptors

      - (NSArray *) whenSortDescriptors
          NSSortDescriptor *sorter;
          sorter = [[[NSSortDescriptor alloc]
                        initWithKey: @"when"
                        ascending: NO] autorelease];

             return ([NSArray arrayWithObject: sorter]);

      } // whenSortDescriptors

      This is for a 'permanent' sorting, not allowing the user to change the sorting. Also,
      new/changed objects added to the collection don't appear to be placed in sorted order.

      Storing Images into the data store (Core Data->General) [permalink]
      So ya want to store an image into the data store. mmalc says

      Don't use the XML store, but instead use the SQLite store

      If an entity has a large data blob as an attribute, you should make a separate entity for that

      e.g. a Person has a 'photo' attribute. Create a Photo entity with a single attribute (the data)
      and a relationship back to the person (if it makes sense, usually it does), and a relationship
      from the Person to the Photo entity.

      This means that the photo data will only be loaded from the persistent store if you actually
      use it.

      (markd: this also has the nice side effect of letting the db put all the blob data elsewhere,
      rather than in with the other data, giving you better locality of reference to your Person
      data without slogging through all the Photo jazz if you don't need it)

      Unslecting all segments with radio - mode tracking (NSSegmentedControl->Hacks)
      NSSegmentedControl won't let you unselect all segments if there is currently one segment
      selected (it's perfectly happy with having everything unselected so long as nothing else is
      selected). This is annoying, so you have to go into the Momentary tracking mode, unselect
      each of the cells, then go back to the original mode.

      In my NSSegmentedControl category, I have a method to solve this problem:

      @interface NSSegmentedControl (BorkwareAdditions)
      - (void) unselectAllSegments;
      // ... other goodies
      @end // NSSegmentedControl

      - (void) unselectAllSegments
          NSSegmentSwitchTracking current;
          current = [self trackingMode];

             [self setTrackingMode: NSSegmentSwitchTrackingMomentary];

             int i;
             for (i = 0; i < [self segmentCount]; i++) {
                 [self setSelected: NO forSegment: i];

             [self setTrackingMode: current];

      } // unselectAllSegments

      Enabling the Safari debug menu (Safari->General) [permalink]
      defaults write IncludeDebugMenu 1

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                       Page 54 of 57
All The Quickies                                                                                         11/20/08 9:07 AM

      defaults write IncludeDebugMenu 1

      console logging in Safari (Safari->General)     [permalink]

          if (window.console) {
            window.console.log ("ook1");

      (window.console exists in Safari, but not in Dashboard)

      Displaying archived web data in a WebView (WebKit->General)            [permalink]

      WebArchive *archive = ... get from somewhere...;

      WebFrame *frame = [webView mainFrame];
      [frame loadArchive: webarchive];

      Opening webview links in the user's default browser. (WebKit->General)               [permalink]

        [someWebView setPolicyDelegate: self];

      - (void) webView:(WebView *)webView
      decidePolicyForNavigationAction:(NSDictionary *)actionInformation
               request:(NSURLRequest *)request
                 frame:(WebFrame *)frame
      decisionListener:(id)listener {
          NSURL *url = [request URL];
          if (url != nil) {
              [[NSWorkspace sharedWorkspace] openURL:url];

      }    // decidePolicyForNavigationAction

      Preventing Safari from displaying PDFs (WebKit->General) [permalink]
      I loathe using Safari to read PDFs. To tell Safari to stop it, try doing

      % defaults write WebKitOmitPDFSupport -bool YES

      if you have the misfortune of having the Acrobat Reader plug-in, you can nuke
      /Library/Internet Plug-Ins/AdobePDFViewer.plugin

      Caveman debugging in both Safari and Dashboard (Dashboard->General) [permalink]
      It'd be too convenient to have a uniform mechanism to perform caveman debugging of
      widgets in both Safari-preview mode (where you can use window.console.log) and Dashboard
      mode (where you can't). Luckily (?), window.alert in Dashboard will log to the console in
      Dashboard, but shows an alert in safari.

      So, combine the two for maximal pleasure:

      function cavemanLog(message) {

          if (window.widget) {
            // Won't display an error box, but will show in the console log.

          } else {
            // Send output to the javascript console.

      } // cavemanLog

      Runing a widget without installing it (Dashboard->General) [permalink]
      When you double-click a widget or open it from the terminal, you get asked if you want to
      install it (which will move your widget to ~/Library/Widgets, which is really annoying
      when it drags it out of your development area. When faced with the dialog, hold down
      command and option to get a "Run" button. That'll run the widget in-pace. If you tun on the

      % defaults write devmode YES

      You can drag widgets out of the dashboard area and have them on-screen. Cmd-R will reload
      the widget.

      Running a pre- canned applescript (AppleScript->General) [permalink]
      Here's a way to run a 'fire and forget' Applescript that lives in your application bundle.

      #define runScriptName @"checknewnow"
      #define runScriptType @"scpt"

      - (IBAction)runScript:(id)sender
          /* Locate that darn thing*/
          NSString *scriptPath = [[NSBundle mainBundle]
                                      pathForResource: runScriptName

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                      Page 55 of 57
All The Quickies                                                                                                  11/20/08 9:07 AM

                                        ofType: runScriptType];
             NSURL *scriptURL = [NSURL fileURLWithPath: scriptPath];

             NSAppleScript *as = [[NSAppleScript alloc]
                                     initWithContentsOfURL: scriptURL
                                     error: nil];
             [as executeAndReturnError: NULL];
             [as release];

      (Thanks to of Chris "The_Tick" Forsythe)

      Format of new pages (VoodooPad->General) [permalink]
      Make a page called NewPageTemplate. Use $title$ for the page term.

      Unladen Swallows ? (VoodooPad->AppleScript)              [permalink]

      tell application "VoodooPad"
      end tell

      Putting an NSXMLDocument into a text view (NSXML->General)                      [permalink]

             NSData *blah = [xmldocument XMLDataWithOptions: NSXMLNodePrettyPrint];
             NSString *snork = [[NSString alloc] initWithData: blah
                                                 encoding: NSUTF8StringEncoding];
             NSAttributedString *arrrgh;
             arrrgh = [[NSAttributedString alloc] initWithString: snork];

             [[xmlTextView textStorage]
                 setAttributedString: [arrrgh autorelease]];

      Reverting all files (Perforce->General)    [permalink]

      % p4 revert -c default ...

      Reverting opened, but unedited files (Perforce->General)               [permalink]

          p4 revert -a

      will revert all files that haven't actually be edited, leaving the edited opened.

      (Thanks to TVL for this one)

      Turning off the executable bit in Perforce (Perforce->General)                 [permalink]

      p4 edit -t text [file_list]
      p4 submit

      (Thanks to TVL for this one)

      Cad Macro (ClanLord->Random) [permalink]
      From Seilk. I can never find it when I want it.

         if @click.simple_name == ""
            if @my.right_item == "caduceus"
                "\use /off\r"
            end if
         else if @click.simple_name == @my.simple_name
            if @my.right_item != "moonstone"
                "\equip \"moonstone\"\r"
            end if
            "\use 3\r"
            if @my.right_item != "caduceus"
                "\equip \"caduceus\"\r"
            end if
            "\use " @click.simple_name "\r"
            message "* Now healing"
         end if

      Binary Searching in a sorted NSArray (NSArray->General) [permalink]
      How do you binary search a sorted NSArray? Use toll free bridging to CFArray which actually
      has a binary search function:

             NSMutableArray *sortedArray = [NSMutableArray arrayWithObjects: @"Alice", @"Beth", @"Carol",@"Ellen",nil];

             //Where is "Beth"?
             unsigned index = (unsigned)CFArrayBSearchValues((CFArrayRef)sortedArray,
                                                              CFRangeMake(0, CFArrayGetCount((CFArrayRef)sortedArray)),
             if (index < [sortedArray count])
                 NSLog(@"Beth was found at index %u", index);
             } else {

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                               Page 56 of 57
All The Quickies                                                                                                11/20/08 9:07 AM

                   NSLog(@"Beth was not found (index is beyond the bounds of sortedArray)");

            //Where should we insert "Debra"?
            unsigned insertIndex = (unsigned)CFArrayBSearchValues((CFArrayRef)sortedArray,
                                                                  CFRangeMake(0, CFArrayGetCount((CFArrayRef)sortedArray)),
            [sortedArray insertObject:@"Debra" atIndex:insertIndex];
            NSLog([sortedArray description]);

            //note: NSArray indices and counts were typed as unsigned. With the move to 64-bit, they are NSUInteger.
            //CFArray indices and counts are CFIndex, which was SInt32 but also will move to 64-bit?
            //Why was it ever signed and will it remain so?

      Muchos Thankos to James Hober for this one.

      Gus Mueller chimed in saying that if you use CFArrayBSearchValues, be sure to sort with
      CFArraySortValues rather than using the Cocoa sorting routines (or at least the
      comparison) - they treat diacritic marks differently, leading to strange errors. From Gus, a
      quick objc addition to NSMutableArray:

      - (void) cfStringSort {
         CFArraySortValues((CFMutableArrayRef)self, CFRangeMake(0, [self count]), (CFComparatorFunction)CFStringCompare, NULL);

      Multiple Objects in one document (Photoshop->General) [permalink]
      Say you have two Smart Objects from ACR or something, and now you want them into one
      document so you can do some layer mask nonsense. To get them into one file do this:
           Open up both files
           Bring the source file up, shift-drag the layer from the palette
           Drag into the image area of the target document

                                    Search Quickies

                   borkware home | products | miniblog | rants | quickies | cocoaheads
                                       Core Programming book

Hosting by Fish Battery

file:///Users/endyh/Documents/Web%20Doc/All%20The%20Quickies.webarchive                                             Page 57 of 57