Structure of the PyObjC package

Introduction

XXX: This documet is outdated and incomplete.

This document gives an overview of the PyObjC for developers (of the package).

One of the sections describes how all of it works, and some of the limitation.

This document is a little dated, it should be updated.

Methods

Classes are scanned for methods when the python wrapper for a class is created. We then create python wrappers for those methods. This way users can use the normal python introspection methods to check which methods are available.

Sadly enough some classes in the Cocoa frameworks on Mac OSX grow new methods when the first instance of those classes is created. We therefore have added some additional code that rescans the method tables on several occasions.

Subclassing

It is possible to subclass objective-C classes in python and this results in a hybrid Python/Objective-C class. Instances of these classes consist of a cluster of 2 objects, a Python object and an Objective-C object.

The reference count (or retainCount in objective-C speak) is stored in the Python object, mostly because that is the only way to maintain a single reference count for the cluster. The pointers from the python half of the cluster to the objective-C half, and the pointers the other way around, are not counted in the reference count. If those would be counted we would introduce cycles that are not detectable by the cycle-breaking garbage collector in python and all python/objective-C hybrids would be immortal.

The first python subclass of an objective-C class introduces a new instance variable in the objective-C object to store the pointer to the python half of the cluster. This variable is always referenced by name. The python half is a subclass of objc_object that already contains a pointer to an objective-C object.

The first python subclass of an objective-C class also introduces a number of methods (both class methods and instance methods) that allow us to maintain the illusion of a single object. Check class-builder.m for details.

Directory structure

Doc/

Documentation

Examples/

Example scripts and applets.

Lib/

Python modules that will be installed in the library. Currently contains the modules/packages 'objc', 'AddressBook', 'AppKit', 'Foundation', 'InterfaceBuilder', 'PreferencePanes', 'PyObjCTools' and 'ScreenSaver.py'.

Modules/

Extension modules related to the packages in 'Lib'. This directory contains both the core module 'objc._objc' and a number of extension modules that help in wrapping all of Cocoa.

Scripts/

Scripts used during building and/or development of PyObjC.

Tools/

Scripts that are useful for users of PyObjC

Reference counts

The Objective-C rules for reference counts are pretty easy: A small number of class methods (alloc, allocWithZone:, copy, ...) transfer object ownership to the caller. For all other objects you have to call 'retain' if you want to keep a reference. This includes all factory methods (e.g. [String stringWithCString:"bla"])!

When programming Cocoa in Python, you almost never need to worry about reference counts: the objc module makes this completely transparent to user. This is mostly implemented in [de]pythonify_c_value. Additonal code is needed when calling methods that transfer ownership of their return value (as described above) and when updating a instance variable in an Objective-C object (retain new and release old, in that order). Both are implemented.

Strings

We currently automatically convert from Python strings to NSStrings (and back). An NSString is represented in Python as a subclass of the 'unicode' class: objc.pyobjc_unicode. This is a conversion as well as a reference to the original NSString. The NSString is accessible in Python with the .nsstring() method, to allow access to NSString's methods (NSMutableString's methods, actually).

Converting a Python string to Objective-C and back currently converts the string to Unicode. If may be useful to try to convert to a normal string (using [NSString dataUsingEncoding:allowLossyConversion:]) and only return a Unicode object if that fails.

When translating from NSString to a Python unicode object (and back) we first translate to a UTF8 encoding. This way we don't have to worry about any differences in the representation of Unicode strings in Python and Objective-C (Python has two different represenations, selection is at compile-time).