Archive for July, 2005

Watching NSEvents

In the midst of investigating how events are passed around within Cocoa and I found some interesting information. Based on the Apple Tech Note - Mac OS X Debugging Magic, it is possible to watch all the events as they are sent.

I was skeptical, but pleasantly surprised to discover that this still works if you have a PyObjC app, including one that is sym-linked! (ie. python setup.py py2app -A)

The magical incantation looks something like:


% defaults write com.mysite.MyApp NSTraceEvents YES
% MyApp.app/Contents/MacOS/MyApp

This will launch the app (MyApp) from the command line, with the events being sent back to the command line. Opening the application as per normal will have the events sent to the Console.

The following will turn of the feature:


% defaults write com.mysite.MyApp NSTraceEvents NO

The results look something like (line breaks added for clarity):


2005-07-27 18:35:57.599 MyApp [2790]
In Application: NSEvent:
type=KeyUp loc=(-395,428) time=152170.8
flags=0x180128 win=0 winNum=15994 ctxt=0xf45f
chars='ƒ' unmodchars='f' repeat=0 keyCode=3

Note: the com.mysite.MyApp bit is actually the value of the CFBundleIdentifier in the Info.plist file. See here for details on setting this up.

DrunkenBlog: On Being and Deliciousness, with Wil Shipley

Another brilliant interview over at DrunkenBlog. Go check it out. Wil Shipley speaks on software, Apple, Cocoa and life.

One of my favourite bits:

Making a simple user interface is a thousand times harder than a complicated one. I could literally write a skeleton of Delicious Library in a day, if I weren’t worried about how all the buttons and fields interacted or looked. Adding the fun to the app is the hard thing …

Opening an AddressBook entry with PyObjC

Having done some user testing on my DateList application, I discovered that they (me and my other test subject) expected something to happen when double clicking on an entry. It seems reasonable to me to open the person in Apple’s AddressBook as the action.

There doesn’t seem to be much information on this, however playing around with the birthday calendar (Tiger iCal feature), there is a URL that seems to work:


addressbook://E15E4D1E-AAE1-4AC2-85DB-98BB906EE988:ABPerson

Passing this to the open shell command opens the appropriate person in AddressBook.

The better question is how to construct one of these. To query an AddressBook entry, we first need to find one. AddressBook has a special reference for the current user called me.


>>> from AddressBook import *
>>> book = ABAddressBook.sharedAddressBook()
>>> book
<ABAddressBook: 0x1133d80>
>>> me = book.me()
>>> type(me)
<objective-c class ABPerson at 0xa4ac3034>

Now that we have a ABPerson, we can determine the UID. The UID property is actually on the base class, ABRecord.


>>> myUID = me.valueForProperty_(kABUIDProperty)
>>> myUID
u'E15E4D1E-AAE1-4AC2-85DB-98BB906EE988:ABPerson'

To open a URL, we need to construct a NSURL:


>>> from Foundation import *
>>> url = NSURL.URLWithString_('addressbook://' + myUID)
>>> url
addressbook://E15E4D1E-AAE1-4AC2-85DB-98BB906EE988:ABPerson

Finally, we pass the NSURL to the openURL_ method of the shared workspace. You get one shared workspace per application, and it can be used for useful things like opening urls, files, applications and some other services such as tracking changes.


>>> from AppKit import *
>>> ws = NSWorkspace.sharedWorkspace()
>>> ws
<NSWorkspace: 0x1134910>
>>> ws.openURL_(url)
1
>>>

openURL_ returns YES (1) if the URL was successfully opened, NO (0) otherwise. At this point AddressBook should open and have selected the entry that you have tagged as you.

Hacking the iTunes library with Python

Bob was having a bit of trouble with his Airport Express. Fortunately for the rest of us, his solution involved delving into the internals of the iTunes library for answers.

Interesting for the simplicity with which PyObjC allows Python idioms to mesh with Apple’s APIs for a neat solution. With a few lines in an interactive shell, Bob manages to locate all the problematic files and set the correct creator code

Ten Essential Development Practices

In this article Damian Conway outlines ten development practices that he considers essential for developing big, business critical systems. Also, incredibly useful for developing big, user critical Cocoa programs.

The examples are in Perl, but the development practices are basic good practice and can be applied to any language.

A short summary:

  1. Design the Module’s Interface First
  2. Write the Test Cases Before the Code
  3. Create Standard Documentation Templates for Modules and Applications
  4. Use a Revision Control System
  5. Create Consistent (Command-Line / User) Interfaces
  6. Agree Upon a Coherent Layout Style and Automate It (with perltidy)
  7. Code in Commented Paragraphs
  8. Throw Exceptions Instead of Returning Special Values or Setting Flags
  9. Add New Test Cases Before you Start Debugging
  10. Don’t Optimize Code—Benchmark It