Archive for Objective C

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 …

PyObjC patterns

PyObjC - First Steps. Bob Ippolito has posted some common usage patterns for calling Objective C from Python.

Even if you have been using PyObjC for a while, this is a refresher worth reading.

Part 2 - Using Address Book and making an app

Having successfully created a simple Cocoa application using Python in Part 1, the next step is to integrate data from Apple’s Address Book (AB).

The PyObjC example of Address Book usage is a good place to start, and the Apple documentation includes any other information needed. I started with the example, played around a bit and then read the documentation mainly for the constants to get the fields I wanted.

The first step is to create a separate file to include the Address Book interaction. I put this into DateList.py. For a simple start, I’ve made the interaction a function that returns the data to the Delegate class. This is called dateFields(), and it creates a connection to the Address Book and loads the fields for it.


import AddressBook

def dateFields():
    book = AddressBook.ABAddressBook.sharedAddressBook()
    return bookFields(book)

bookFields generates the actual list using a list comprehension. validPerson filters the list to only include records which have the birthday field set.


def validPerson(person):
    return person.valueForProperty_(
        AddressBook.kABBirthdayProperty) != None

def bookFields(book):
    return [ personToFields(p) 
        for p in book.people() if validPerson(p) ]

I’m still in awe over how nicely the PyObjC does the translation behind the scenes. The native python list constructs loop effortlessly across the Objective C objects.

The next part in the story is to actually create the tuple with the person’s name and birthday. If you recall, this should look something like:


{'date': 1977-08-04 12:00:00 GMT, 'name': u'Geoff Wilson'}

I’ve hidden this away in the personToFields function, with two functions to get some details, as follows:


def personToFields(person):
    return {
        'date': getBirthday(person),
        'name': getPersonName(person)
    }

def getPersonName(person):
   return person.valueForProperty_(
        AddressBook.kABFirstNameProperty
        ) + ' ' 
        + person.valueForProperty_(
        AddressBook.kABLastNameProperty)

def getBirthday(person):
    return person.valueForProperty_(
        AddressBook.kABBirthdayProperty)

At this stage you should have enough code to be able to query your Address Book. Python allows you to add the equivalent of a main function to a source file. Similar to the Java usage, I’ve used this to write quick test code to my module. Better would be to write unit test cases, but this isn’t an example of TDD.

Add the following to your code:


if __name__ == '__main__':
    print dateFields()

And then run the result:


% python DateList.py
[{'date': 2004-04-04 12:00:00 Australia/Melbourne,
'name': u'Test User'}]
%

Note: if you don’t have any records in Address Book, you won’t see any results.

The change to integrate this into the user interface is to update the delegate to request the data from the dateFields() function. You also need to add the appropriate import call:


from PyObjCTools import NibClassBuilder
from DateList import dateFields

NibClassBuilder.extractClasses('MainMenu')

class DateListDelegate(NibClassBuilder.AutoBaseClass):
    def items(self):
        return dateFields()

The magical bit is that there is no need to re-compile and no need to change the user interface. You should now see something like:

Birthday list

The source code for the sample application from this tutorial is available here.

PyObjC released for Tiger (and other stuff)

PyObjC has been officially released for Tiger. This is a big upgrade, and includes wrappers for some of the new Tiger technologies, better py2app support and a heap of bug fixes.

So if you weren’t happy following the dev release using subversion, you now have no excuses. Oh yeah, and it will still work on 10.3, with some testing done for 10.2 (if you are still using 10.2 and have issues, please use the mailing list to let the developers know of any issues).

I also found a nice article if you want to start right from the beginning of almost no development knowledge at all for creating Python based Objective C applications. Assumes no knowledge of XCode or Interface Builder (IB) or python for that matter.

For something more interesting, xml.com have a very good article, Unicode Secrets by Uche Ogbuji, which explains how to use unicode properly in Python. Essential reading if you have even vague thoughts of ever using XML in an application.

PyObjC support for Tiger

PyObjC adds support for Tiger specific technologies - however not in the current released build. You currently need to grab the source via subversion.

First, download subversion for Mac OS X from Martin Ott’s site. The 10.3 installer seems to work okay for 10.4.

Second, follow the instructions for downloading the PyObjC source:

svn co http://svn.red-bean.com/pyobjc/trunk/pyobjc/

Finally, follow the installation instructions. The short version is:

cd pyobjc
python setup.py bdist_mpkg --open

And then follow the instructions in the installer.