objc – The PyObjC bridge

Platforms: MacOS X

Introduction

The module objc is the core of PyObjC and provides the automatic bridging between Python and Objective-C. It also provides a number of utility functions and types that make it easier to integrate Python and Objective-C code.

The module objc defines a number of functions whose names start with an underscore. Those functions are private and should not be used, they can be removed from release without warning.

NOTE: This document is currently mostly an exhaustive list of stuff and needs to be reorganised once I’ve filled in the technical details.

Debugging

objc.setVerbose(yesOrNo)

When the argument is True the bridge will log more information.

This currently results in output on the standard error stream whenever an exception is translated from Python to Objective-C.

objc.getVerbose()
Returns the current value of the verbose flag.

Tweaking behaviour

objc.setUseKVOForSetattr()
TODO
objc.setHideProtected(yesOrNo)

When the argument is True protected methods of an Objective-C class will not be included in the output of dir(). Protected methods are those whose selector starts with an underscore.

This option is on by default.

objc.setStrBrigeEnabled()

TODO

This function is not available in Python 3.x

objc.getStrBridgeEnabled()

TODO

This function is not available in Python 3.x

Utilities

objc.allocateBuffer()
TODO
objc.CFToObject()
TODO
objc.ObjectToCF()
TODO

Accessing classes and protocols

objc.lookUpClass(classname)
Parameter:classname (string) – the name of an Objective-C class
Returns:the named Objective-C class
Raise:objc.nosuchclass_error when the class does not exist
objc.getClassList()
Returns:a list of a classes known to the Objective-C runtime
objc.protocolsForClass()
TODO
objc.protocolsForProcess()
TODO
objc.propertiesForClass(objcClass)
Returns:a list of properties from the Objective-C runtime

The return value is a list with information about properties on this class or protocol from the Objective-C runtime. This does not include properties superclasses.

Every entry in the list is dictionary with the following keys:

Key Description
name Name of the property (a string)
raw_attr Raw value of the attribute string (a byte string)
typestr The type string for this attribute (a byte string)
classname When the type string is objc._C_ID this is the name of the Objective-C class (a string).
readonly True iff the property is read-only (bool)
copy True iff the property is copying the value (bool)
retain True iff the property is retaining the value (bool)
nonatomic True iff the property is not atomic (bool)
dynamic True iff the property is dynamic (bool)
weak True iff the property is weak (bool)
collectable True iff the property is collectable (bool)
getter Non-standard selector for the getter method (a byte string)
setter Non-standard selector for the setter method (a byte string)

All values but name and raw_attr are optional. The other attributes contain a decoded version of the raw_attr value. The boolean attributes should be interpreted as False when the aren’t present.

The documentation for the Objective-C runtime contains more information about property definitions.

This function only returns information about properties as they are defined in the Objective-C runtime, that is using @property definitions in an Objective-C interface. Not all properties as they are commonly used in Objective-C are defined using that syntax, especially properties in classes that were introduced before MacOSX 10.5.

This function always returns an empty list on MacOS X 10.4.

New in version 2.3.

objc.listInstanceVariables()
TODO
objc.getInstanceVariable()
TODO
objc.setInstanceVariable()
TODO
objc.protocolNamed()
TODO
exception objc.ProtocolError
TODO

Dynamic modification of classes

objc.classAddMethods()
TODO
objc.classAddMethod()
TODO (Lib/objc/_category)
class objc.Category
TODO (Lib/objc/_category)

Plugin bundles

objc.currentBundle()
TODO
objc.registerPlugin()
TODO: Deprecated
objc.pluginBundle()
TODO: Deprecated

Memory management

PyObjC automaticly manages Cocoa reference counts for you, the functions in this section help in finetuning this behaviour.

objc.recycleAutoreleasePool()
Flush the NSAutoreleasePool that PyObjC creates on import. Use this before entering the application main loop when you do a lot of work before starting the main loop.
objc.removeAutoreleasePool()
Use this in plugin bundles to remove the release pool that PyObjC creates on import. In plugins this pool will interact in unwanted ways with the embedding application.

Test support

The functions in this section are present as support code for PyObjC’s unittests and are not part of the stable API. Please let us know if you use these functions in your code.

objc.splitSignature(typestring)

Split an encoded Objective-C signature string into the encoding strings for seperate types.

Parameter:typestring (byte string) – an encoded method signature
Returns:list of type signatures
Return type:list of byte strings
objc.splitStruct(typestring)
TODO.
objc.repythonify()
TODO

Framework wrappers

objc.setSignatureForSelector()
TODO
objc.pyobjc_id()
TODO
objc.loadBundle()
TODO
objc.registerCFSignature()
TODO
objc.loadBundleVariables()
TODO
objc.loadSpecialVar()
TODO
objc.loadBundleFunctions()
TODO
objc._loadFunctionList()
TODO
objc.createOpaquePointerType()
TODO
objc.createStructType()
TODO
objc.registerMetaDataForSelector()
TODO
objc.parseBridgeSupport()
TODO
objc.registerListType()
TODO (Lib/objc/_bridges)
objc.registerMappingType()
TODO (Lib/objc/_bridges)
objc.initFrameworkWrapper()
TODO
objc.addConvenienceForSelector()
TODO
objc.addConvenienceForClass()
TODO
objc._setClassSetUpHook()

This is a private hook that is called during the creation of a subclass.

WARNING: This hook is not part of the stable API.

New in version 2.3.

objc._setClassExtender()

This is a private hook that’s called during the creation of the proxy for an Objective-C class.

WARNING: This hook is not part of the stable API.

New in version 2.2.

Changed in version 2.3: TODO: In version 2.2 the hook gets called any time the bridge rescans a class, in 2.3 the hook only gets called during initial construction and has less oportunity to change things.

Types

class objc.objc_class
TODO: the meta class for Objective-C classes
class objc.objc_object
TODO: the root class for Objective-C classes
class objc.pyobjc_unicode
TODO: proxy for NSString*
class objc.selector
TODO: an Objective-C method reference
class objc.FSRef
TODO: proxy for FSRef
class objc.FSSPec
TODO: proxy for FSSpec
class objc.ivar
TODO: an instance variable reference
class objc.informal_protocol
TODO: add section about protocols
class objc.formal_protocol
TODO: add section about protocols
class objc.varlist
TODO: a varlist is a list of indeteriminate length
class objc.function
TODO: a global function in a framework.
class objc.IMP
TODO: proxy for IMP
class objc.super

This is a subclass of super that works properly for Objective-C classes as well as regular Python classes.

The statement from Framework import * will replace the regular super by this class.

Constants

objc.nil
Alias for None, for easier translation of existing Objective-C code.
objc.YES
Alias for True, for easier translation of existing Objective-C code.
objc.NO
Alias for False, for easier translation of existing Objective-C code.
objc.NULL
TODO: add description of pass by reference arguments and the difference between None and NULL
objc.MAC_OS_X_VERSION_MAX_ALLOWED
The value of MAC_OS_X_VERSION_MAX_ALLOWED when PyObjC was compiled.
objc.MAC_OS_X_VERSION_MIN_REQUIRED
The value of MAC_OS_X_VERSION_MIN_REQUIRED when PyObjC was compiled.
objc.MAC_OS_X_VERSION_10_N
There are currently 6 constants of this form, for N from 1 to 6, and these have the same value as the Objective-C constant of the same name.
objc.platform
This always has the value "MACOSX".

Objective-C type strings

The Objective-C runtime and the PyObjC bridge represent the types of instance variables and methods arguments and return values as a string with a compact representation. The Python representation of that string is a byte string (that is type bytes in Python 3.x and str in Python 2.x).

Basic types

The representation for basic types is a single character, the table below lists symbolic constants in the for those constants.

Name Objective-C type
_C_ID id (an Objective-C instance)
_C_CLASS an Objective-C class
_C_SEL a method selector
_C_CHR char
_C_UCHR unsigned char
_C_SHT short
_C_USHT unsigned short
_C_BOOL bool (or _Bool)
_C_INT int
_C_UINT unsigned int
_C_LNG long
_C_ULNG unsigned long
_C_LNG_LNG long long
_C_ULNG_LNG unsigned long long
_C_FLT float
_C_DBL double
_C_VOID void
_C_UNDEF “other” (such a function)
_C_CHARPTR C string (char*)
_C_NSBOOL BOOL
_C_UNICHAR UniChar
_C_CHAR_AS_TEXT char when uses as text or a byte array
_C_CHAR_AS_INT int8_t (or char when
used as a number)

The values _C_NSBOOL, _C_UNICHAR, _C_CHAR_AS_TEXT and _C_CHAR_AS_INT are inventions of PyObjC and are not used in the Objective-C runtime.

Complex types

More complex types can be represented using longer type strings:

  • a pointer to some type is _C_PTR followed by the type string of the pointed-to type.

  • a bitfield in a structure is represented as _C_BFLD followed by an integer with the number of bits.

    Note that PyObjC cannot convert bitfields at this time.

  • a C structure is represented as _C_STRUCT_B followed by the struct name, followed by '=', followed by the encoded types of all fields followed by _C_STRUCT_E. The field name (including the closing equals sign) is optional.

  • a C union is represented as _C_UNION_B followed by the struct name, followed by '=', followed by the encoded types of all fields followed by _C_UNION_E. The field name (including the closing equals sign) is optional.

    Note that PyObjC cannot convert C unions at this time.

  • a C array is represented as _C_ARY_B followed by an integer representing the number of items followed by the encoded element type, followed by _C_ARY_E.

  • The C construct ‘const’ is mapped to _C_CONST, that is a const char* is represented as _C_CONST + _C_CHARPTR.

Additional annotations for method and function arguments

Method arguments can have prefixes that closer describe their functionality. Those prefixes are inheritted from Distributed Objects are not used by the Objective-C runtime, but are used by PyObjC.

  • When a pointer argument is an input argument it is prefixed by _C_IN.
  • When a pointer argument is an output argument it is prefixed by _C_OUT.
  • When a pointer argument is an input and output argument it is prefixed by _C_INOUT.
  • Distributed objects uses the prefix _C_BYCOPY to tell that a value should be copied to the other side instead of sending a proxy reference. This is not used by PyObjC.
  • Distributed objects uses the prefix _C_ONEWAY on the method return type to tell that the method result is not used and the caller should not wait for a result from the other side. This is not used by PyObjC.

When a pointer argument to a function prefixed by _C_IN, _C_OUT or _C_INOUT the brige assumes that it is a pass by reference argument (that is, a pointer to a single value), unless other information is provided to the bridge.

TODO: Write how to write Objective-C code to ensure that the right prefixes are added by the compiler.

Special encoded types

The table below shows constants for a number of C types that are used in Cocoa but are not basic C types.

Constant Objective-C type
_C_CFTYPEID CFTypeID
_C_NSInteger NSInteger
:const`:_C_NSUInteger` NSUInteger
_C_CFIndex CFIndex
_C_CGFloat CGFloat
_sockaddr_type struct sockaddr

Context pointers

A number of Objective-C APIs have one argument that is a context pointer, which is a void*. In Objective-C your can pass a pointer to an arbitrary value, in Python this must be an integer.

PyObjC provides a context object that can be used to allocate unique integers and map those to objects.

(NOTE: The markup below here is probably incorrect)

context.register(value)

Add a value to the context registry.

Parameter:value – An arbitrary object
Returns:A unique integer that’s suitable to be used as a context pointer
context.unregister(value):

Remove an object from the context registery, this object must be have been added to the registry before.

Parameter:value – An object in the context registry
context.get()
Retrieve an object from the registry given the return value from context.register.

Descriptors

objc.IBOutlet([name])

Creates an instance variable that can be used as an outlet in Interface Builder. When the name is not specified the bridge will use the name from the class dictionary.

The code block below defines an instance variable named “button” and makes that available as an outlet in Interface Builder.

class SomeObject (NSObject):

    button = IBOutlet()
objc.IBAction()

Mark an method as an action for use in Interface Builder.

Usage:

class SomeObject (NSObject):

   @IBAction
   def saveDocument_(self, sender):
       pass
objc.instancemethod()

Explicitly mark a method as an instance method. Use this when PyObjC incorrectly deduced that a method should be a class method.

Usage:

class SomeObject (NSObject):

   @instancemethod
   def alloc(self):
       pass
objc.accessor()
Use this decorator on the definition of accessor methods to ensure that it gets the right method signature in the Objective-C runtime.
objc.typedAccessor(valueType)

Use this decorator on the definition of accessor methods to ensure that it gets the right method signature in the Objective-C runtime.

The valueType is the encoded string for a single value.

objc.typedSelector()

Use this decorator to explicitly set the type signature for a method.

An example:

@typedSelector(b'I@:d')
def makeUnsignedIntegerOfDouble_(self, d):
   return d
objc.namedSelector(name[, signature])
Use this decorator to explictly set the Objective-C method name instead of deducing it from the Python name. You can optionally set the method signature as well.
objc.callbackFor(callable, argIndex=-1)

Use this decorator to tell that this function is the callback for an (Objective-C) API.

TODO: further describe

objc.selectorFor()

Decorator to tell that this is the “callback” selector for another API.

TODO: further describe

objc.synthesize()

Use this to synthesize a property with getter and setter methods.

TODO: futher describe

Interacting with @synchronized blocks

PyObjC provides an API that implements locking in the same way as the @synchronized statement in Objective-C.

with object_lock(anNSObject):
    pass
class objc.object_lock(value)

This class represents the mutex that protects an Objective-C object for the @synchronized statement. This can be used as a context manager for the with statement, but can also be used standalone.

lock()
Acquire the object mutex
unlock()
Release the object mutex

Archiving Python and Objective-C objects

Python and Objective-C each provide a native object serialization method, the pickle module in Python and the NSCoding protocol in Objective-C.

It is possible to use an NSKeyedArchiver to store any Python object that can be pickled in an Objective-C serialized data object.

Due to technical details it is not possible to pickle an Objective-C object, unless someone explicitly implements the pickle protocol for such an object.

Properties

Introduction

Both Python and Objective-C have support for properties, which are object attributes that are accessed using attribute access syntax but which result in a method call.

The Python built-in property is used to define new properties in plain Python code. These properties don’t full interoperate with Objective-C code though because they do not necessarily implement the Objective-C methods that mechanisms like Key-Value Coding use to interact with a class.

PyObjC therefore has a number of property classes that allow you to define new properties that do interact fully with the Key-Value Coding and Observation frameworks.

TODO: Implement method for enabling properties on existing classes and tell why that is off by default and when it will be turned on by default.

TODO: The description is way to minimal, even the design document contained more information.

class objc.object_property(name=None, read_only=False, copy=False, dynamic=False, ivar=None, typestr=_C_ID, depends_on=None)
Parameters:
  • name – Name of the property, the default is to extract the name from the class dictionary
  • read_only – Is this a read-only property? The default is a read-write property.
  • copy – Should the default setter method copy values? The default retains the new value without copying.
  • dynamic – If this argument is True the property will not generate default accessor,

but will rely on some external process to create them. :param ivar: Name of the instance variable that’s used to store the value. When this value is None the name will be calculated from the property name. If it is NULL there will be no instance variable. :param typestr: The Objective-C type for this property, defaults to an arbitrary object. :param depends_on: A sequence of names of properties the value of this property depends on.

During the class definition you can add accessor methods by using the property as a decorator

object_property.getter()

Decorator for defining the getter method for a property. The name of the method should be the same as the property:

class MyObject (NSObject):

    prop = objc.object_property()

    @prop.getter
    def prop(self):
       return 42
object_property.setter()
Decorator for defining the setter method for a property. The name of the method should be the same as the property.
object_property.validate()
Decorator for defining a Key-Value Coding validator for this property.

It is possible to override property accessor in a subclass:

class MySubclass (MyObject):
    @MyObject.prop.getter
    def getter(self):
        return "the world"

This can also be used to convert a read-only property to a read-write one by adding a setter accessor.