rubicon.objc.api — The high-level Rubicon API

This module contains Rubicon’s main high-level APIs, which allow easy interaction with Objective-C classes and objects using Pythonic syntax.

Nearly all attributes of this module are also available on the main rubicon.objc module, and if possible that module should be used instead of importing rubicon.objc.api directly.

Objective-C objects

class rubicon.objc.api.ObjCInstance(ptr)

Python wrapper for an Objective-C instance.

The constructor accepts an objc_id or anything that can be cast to one, such as a c_void_p, or an existing ObjCInstance.

ObjCInstance objects are cached — this means that for every Objective-C object there can be at most one ObjCInstance object at any time. Rubicon will automatically create new ObjCInstances or return existing ones as needed.

The returned object’s Python class is not always exactly ObjCInstance. For example, if the passed pointer refers to a class or a metaclass, an instance of ObjCClass or ObjCMetaClass is returned as appropriate. Additional custom ObjCInstance subclasses may be defined and registered using register_type_for_objcclass(). Creating an ObjCInstance from a nil pointer returns None.

Rubicon currently does not perform any automatic memory management on the Objective-C object wrapped in an ObjCInstance. It is the user’s responsibility to retain and release wrapped objects as needed, like in Objective-C code without automatic reference counting.

ptr
_as_parameter_

The wrapped object pointer as an objc_id. This attribute is also available as _as_parameter_ to allow ObjCInstances to be passed into ctypes functions.

objc_class

The Objective-C object’s class, as an ObjCClass.

__str__()

Get a human-readable representation of self.

By default, self.description converted to a Python string is returned. If self.description is nil, self.debugDescription converted to a Python is returned instead. If that is also nil, repr(self) is returned as a fallback.

__repr__()

Get a debugging representation of self, which includes the Objective-C object’s class and debugDescription.

__getattr__(name)

Allows accessing Objective-C properties and methods using Python attribute syntax.

If self has a Python attribute with the given name, its value is returned.

If there is an Objective-C property with the given name, its value is returned using its getter method. An attribute is considered a property if any of the following are true:

  • A property with the name is present on the class (i.e. declared using @property in the source code)

  • There is both a getter and setter method for the name

  • The name has been declared as a property using ObjCClass.declare_property()

Otherwise, a method matching the given name is looked up. ObjCInstance understands two syntaxes for calling Objective-C methods:

  • “Flat” syntax: the Objective-C method name is spelled out in the attribute name, with all colons replaced with underscores, and all arguments are passed as positional arguments. For example, the Objective-C method call [self initWithWidth:w height:h] translates to self.initWithWidth_height_(w, h).

  • “Interleaved” syntax: the Objective-C method name is split up between the attribute name and the keyword arguments passed to the returned method. For example, the Objective-C method call [self initWithRed:r green:g blue:b] translates to self.initWithRed(r, green=g, blue=b).

The “interleaved” syntax is usually preferred, since it looks more similar to normal Objective-C syntax. However, the “flat” syntax is also fully supported. Certain method names require the “flat” syntax, for example if two arguments have the same label (e.g. performSelector:withObject:withObject:), which is not supported by Python’s keyword argument syntax.

Warning

The “interleaved” syntax currently ignores the ordering of its keyword arguments. However, in the interest of readability, the keyword arguments should always be passed in the same order as they appear in the method name.

This also means that two methods whose names which differ only in the ordering of their keywords will conflict with each other, and can only be called reliably using “flat” syntax.

As of Python 3.6, the order of keyword arguments passed to functions is preserved (PEP 468). In the future, once Rubicon requires Python 3.6 or newer, “interleaved” method calls will respect keyword argument order. This will fix the kind of conflict described above, but will also disallow specifying the keyword arguments out of order.

__setattr__(name, value)

Allows modifying Objective-C properties using Python syntax.

If self has a Python attribute with the given name, it is set. Otherwise, the name should refer to an Objective-C property, whose setter method is called with value.

rubicon.objc.api.objc_const(dll, name)

Create an ObjCInstance from a global pointer variable in a CDLL.

This function is most commonly used to access constant object pointers defined by a library/framework, such as NSCocoaErrorDomain.

Objective-C classes

class rubicon.objc.api.ObjCClass(name_or_ptr[, bases, attrs[, protocols=(), auto_rename=None]])

Python wrapper for an Objective-C class.

ObjCClass is a subclass of ObjCInstance and supports the same syntaxes for calling methods and accessing properties.

The constructor accepts either the name of an Objective-C class to look up (as str or bytes), or a pointer to an existing class object (in any form accepted by ObjCInstance).

If given a pointer, it must refer to an Objective-C class; pointers to other objects are not accepted. (Use ObjCInstance to wrap a pointer that might also refer to other kinds of objects.) If the pointer refers to a metaclass, an instance of ObjCMetaClass is returned instead. Creating an ObjCClass from a Nil pointer returns None.

ObjCClass can also be called like type, with three arguments (name, bases list, namespace mapping). This form is called implicitly by Python’s class syntax, and is used to create a new Objective-C class from Python (see Creating custom Objective-C classes and protocols). The bases list must contain exactly one ObjCClass to be extended by the new class. An optional protocols keyword argument is also accepted, which must be a sequence of ObjCProtocols for the new class to adopt.

If the name of the class has already registered with the Objective C runtime, the auto_rename option can be used to ensure that the Objective C name for the new class will be unique. A numeric suffix will be appended to the Objective C name to ensure uniqueness (for example, MyClass will be renamed to MyClass_2, MyClass_3 etc until a unique name is found). By default, classes will not be renamed, unless ObjCClass.auto_rename is set at the class level.

name

The name of this class, as a str.

superclass

The superclass of this class, or None if this is a root class (such as NSObject).

protocols

The protocols adopted by this class.

auto_rename = False

A bool value describing whether a defined class should be renamed automatically if a class with the same name already exists in the Objective C runtime.

declare_property(name)

Declare the instance method name to be a property getter.

This causes the attribute named name on instances of this class to be treated as a property rather than a method — accessing it returns the property’s value, without requiring an explicit method call. See ObjCInstance.__getattr__ for a full description of how attribute access behaves for properties.

Most properties do not need to be declared explicitly using this method, as they are detected automatically by ObjCInstance.__getattr__. This method only needs to be used for properties that are read-only and don’t have a @property declaration in the source code, because Rubicon cannot tell such properties apart from normal zero-argument methods.

Note

In the standard Apple SDKs, some properties are introduced as regular methods in one system version, and then declared as properties in a later system version. For example, the description method/property of NSObject was declared as a regular method up to OS X 10.9, but changed to a property as of OS X 10.10.

Such properties cause compatibility issues when accessed from Rubicon: obj.description() works on 10.9 but is a TypeError on 10.10, whereas obj.description works on 10.10 but returns a method object on 10.9. To solve this issue, the property can be declared explicitly using NSObject.declare_property('description'), so that it can always be accessed using obj.description.

declare_class_property(name)

Declare the class method name to be a property getter.

This is equivalent to self.objc_class.declare_property(name).

__instancecheck__(instance)

Check whether the given object is an instance of this class.

If the given object is not an Objective-C object, False is returned.

This method allows using ObjCClasses as the second argument of isinstance(): isinstance(obj, NSString) is equivalent to obj.isKindOfClass(NSString).

__subclasscheck__(subclass)

Check whether the given class is a subclass of this class.

If the given object is not an Objective-C class, TypeError is raised.

This method allows using ObjCClasses as the second argument of issubclass(): issubclass(cls, NSValue) is equivalent to obj.isSubclassOfClass(NSValue).

class rubicon.objc.api.ObjCMetaClass(name_or_ptr)

Python wrapper for an Objective-C metaclass.

ObjCMetaClass is a subclass of ObjCClass and supports almost exactly the same operations and methods. However, there is usually no need to look up a metaclass manually. The main reason why ObjCMetaClass is a separate class is to differentiate it from ObjCClass in the repr(). (Otherwise there would be no way to tell classes and metaclasses apart, since metaclasses are also classes, and have exactly the same name as their corresponding class.)

The constructor accepts either the name of an Objective-C metaclass to look up (as str or bytes), or a pointer to an existing metaclass object (in any form accepted by ObjCInstance).

If given a pointer, it must refer to an Objective-C metaclass; pointers to other objects are not accepted. (Use ObjCInstance to wrap a pointer that might also refer to other kinds of objects.) Creating an ObjCMetaClass from a Nil pointer returns None.

Standard Objective-C and Foundation classes

The following classes from the Objective-C runtime and the Foundation framework are provided as ObjCClasses for convenience. (Other classes not listed here can be looked up by passing a class name to the ObjCClass constructor.)

Note

None of the following classes have a usable Python-style constructor - for example, you cannot call NSString("hello") to create an Objective-C string from a Python string. To create instances of these classes, you should use ns_from_py() (also called at()): ns_from_py("hello") returns a NSString instance with the value hello.

class rubicon.objc.api.NSObject

The NSObject class from <objc/NSObject.h>.

Note

See the ObjCInstance documentation for a list of operations that Rubicon supports on all objects.

debugDescription
description

These Objective-C properties have been declared using ObjCClass.declare_property() and can always be accessed using attribute syntax.

class rubicon.objc.api.Protocol

The Protocol class from <objc/Protocol.h>.

Note

This class has no (non-deprecated) Objective-C methods; protocol objects can only be manipulated using Objective-C runtime functions. Rubicon automatically wraps all Protocol objects using ObjCProtocol, which provides an easier interface for working with protocols.

class rubicon.objc.api.NSNumber

The NSNumber class from <Foundation/NSValue.h>.

Note

This class can be converted to and from standard Python primitives (bool, int, float) using py_from_ns() and ns_from_py().

class rubicon.objc.api.NSDecimalNumber

The NSDecimalNumber class from <Foundation/NSDecimalNumber.h>.

Note

This class can be converted to and from Python decimal.Decimal using py_from_ns() and ns_from_py().

class rubicon.objc.api.NSString

The NSString class from <Foundation/NSString.h>.

This class also supports all methods that str does.

Note

This class can be converted to and from Python str using py_from_ns() and ns_from_py(). You can also call str(nsstring) to convert a NSString to str.

NSString objects consist of UTF-16 code units, unlike str, which consists of Unicode code points. All NSString indices and iteration are based on UTF-16, even when using the Python-style operations/methods. If indexing or iteration based on code points is required, convert the NSString to str first.

__str__()

Return the value of this NSString as a str.

UTF8String

This Objective-C property has been declared using ObjCClass.declare_property() and can always be accessed using attribute syntax.

class rubicon.objc.api.NSData

The NSData class from <Foundation/NSData.h>.

Note

This class can be converted to and from Python bytes using py_from_ns() and ns_from_py().

class rubicon.objc.api.NSArray

The NSArray class from <Foundation/NSArray.h>.

Note

This class can be converted to and from Python list using py_from_ns() and ns_from_py().

py_from_ns(nsarray) will recursively convert nsarray’s elements to Python objects, where possible. To avoid this recursive conversion, use list(nsarray) instead.

ns_from_py(pylist) will recursively convert pylist’s elements to Objective-C. As there is no way to store Python object references as Objective-C objects yet, this recursive conversion cannot be avoided. If any of pylist’s elements cannot be converted to Objective-C, an error is raised.

__getitem__(index)
__len__()
__iter__()
__contains__(value)
__eq__(other)
__ne__(other)
index(value)
count(value)
copy()

Python-style sequence interface.

class rubicon.objc.api.NSMutableArray

The NSMutableArray class from <Foundation/NSArray.h>.

Note

This class can be converted to and from Python exactly like its superclass NSArray.

__setitem__(index, value)
__delitem__(index)
append(value)
clear()
extend(values)
insert(index, value)
pop([index=-1])
remove(value)
reverse()

Python-style mutable sequence interface.

class rubicon.objc.api.NSDictionary

The NSDictionary class from <Foundation/NSDictionary.h>.

Note

This class can be converted to and from Python dict using py_from_ns() and ns_from_py().

py_from_ns(nsdict) will recursively convert nsdict’s keys and values to Python objects, where possible. To avoid the recursive conversion of the values, use {py_from_ns(k): v for k, v in nsdict.items()}. The conversion of the keys cannot be avoided, because Python dict keys need to be hashable, which ObjCInstance is not. If any of the keys convert to a Python object that is not hashable, an error is raised (regardless of which conversion method you use).

ns_from_py(pydict) will recursively convert pydict’s keys and values to Objective-C. As there is no way to store Python object references as Objective-C objects yet, this recursive conversion cannot be avoided. If any of pydict’s keys or values cannot be converted to Objective-C, an error is raised.

__getitem__(key)
__len__()
__iter__()
__contains__(key)
__eq__(other)
__ne__(other)
copy()
get(key[, default=None])
keys()
items()
values()

Python-style mapping interface.

Note

Unlike most Python mappings, NSDictionary’s keys, values, and items methods don’t return dynamic views of the dictionary’s keys, values, and items.

keys and values return lists that are created each time the methods are called, which can have an effect on performance and memory usage for large dictionaries. To avoid this, you can cache the return values of keys and values, or convert the NSDictionary to a Python dict beforehand.

items is currently implemented as a generator, meaning that it returns a single-use iterator. If you need to iterate over items more than once or perform other operations on it, you should convert it to a Python set or list first.

class rubicon.objc.api.NSMutableDictionary

The NSMutableDictionary class from <Foundation/NSDictionary.h>.

Note

This class can be converted to and from Python exactly like its superclass NSDictionary.

__setitem__(key, value)
__delitem__(key)
clear()
pop(item[, default])
popitem()
setdefault(key[, default=None])
update([other, ]**kwargs)

Python-style mutable mapping interface.

Objective-C protocols

class rubicon.objc.api.ObjCProtocol(name_or_ptr[, bases, attrs[, auto_rename=None]])

Python wrapper for an Objective-C protocol.

The constructor accepts either the name of an Objective-C protocol to look up (as str or bytes), or a pointer to an existing protocol object (in any form accepted by ObjCInstance).

If given a pointer, it must refer to an Objective-C protocol; pointers to other objects are not accepted. (Use ObjCInstance to wrap a pointer that might also refer to other kinds of objects.) Creating an ObjCProtocol from a nil pointer returns None.

ObjCProtocol can also be called like type, with three arguments (name, bases list, namespace mapping). This form is called implicitly by Python’s class syntax, and is used to create a new Objective-C protocol from Python (see Creating custom Objective-C classes and protocols). The bases list can contain any number of ObjCProtocol objects to be extended by the new protocol.

If the name of the protocol has already registered with the Objective C runtime, the auto_rename option can be used to ensure that the Objective C name for the new protocol will be unique. A numeric suffix will be appended to the Objective C name to ensure uniqueness (for example, MyProtocol will be renamed to MyProtocol_2, MyProtocol_3 etc until a unique name is found). By default, protocols will not be renamed, unless ObjCProtocol.auto_rename is set at the class level.

name

The name of this protocol, as a str.

protocols

The protocols that this protocol extends.

auto_rename = False

A bool value whether a defined protocol should be renamed automatically if a protocol with the same name is already exists.

__instancecheck__(instance)

Check whether the given object conforms to this protocol.

If the given object is not an Objective-C object, False is returned.

This method allows using ObjCProtocols as the second argument of isinstance(): isinstance(obj, NSCopying) is equivalent to obj.conformsToProtocol(NSCopying).

__subclasscheck__(subclass)

Check whether the given class or protocol conforms to this protocol.

If the given object is not an Objective-C class or protocol, TypeError is raised.

This method allows using ObjCProtocols as the second argument of issubclass(): issubclass(cls, NSCopying) is equivalent to cls.conformsToProtocol(NSCopying), and issubclass(proto, NSCopying) is equivalent to protocol_conformsToProtocol(proto, NSCopying)).

Standard Objective-C and Foundation protocols

The following protocols from the Objective-C runtime and the Foundation framework are provided as ObjCProtocols for convenience. (Other protocols not listed here can be looked up by passing a protocol name to the ObjCProtocol constructor.)

rubicon.objc.api.NSObjectProtocol

The NSObject protocol from <objc/NSObject.h>. The protocol is exported as NSObjectProtocol in Python because it would otherwise clash with the NSObject class.

Converting objects between Objective-C and Python

rubicon.objc.api.py_from_ns(nsobj)

Convert a Foundation object into an equivalent Python object if possible.

Currently supported types:

Other objects are returned unmodified as an ObjCInstance.

rubicon.objc.api.ns_from_py(pyobj)

Convert a Python object into an equivalent Foundation object. The returned object is autoreleased.

This function is also available under the name at(), because its functionality is very similar to that of the Objective-C @ operator and literals.

Currently supported types:

Other types cause a TypeError.

rubicon.objc.api.at(pyobj)

Alias for ns_from_py().

Creating custom Objective-C classes and protocols

Custom Objective-C classes are defined using Python class syntax, by subclassing an existing ObjCClass object:

class MySubclass(NSObject):
    # method, property, etc. definitions go here

A custom Objective-C class can only have a single superclass, since Objective-C does not support multiple inheritance. However, the class can conform to any number of protocols, which are specified by adding the protocols keyword argument to the base class list:

class MySubclass(NSObject, protocols=[NSCopying, NSMutableCopying]):
    # method, property, etc. definitions go here

Note

Rubicon requires specifying a superclass when defining a custom Objective-C class. If you don’t need to extend any specific class, use NSObject as the superclass.

Although Objective-C technically allows defining classes without a base class (so-called root classes), this is almost never the desired behavior (attempting to do so causes a compiler error by default). In practice, this feature is only used in the definitions of core Objective-C classes like NSObject. Because of this, Rubicon does not support defining Objective-C root classes.

Similar syntax is used to define custom Objective-C protocols. Unlike classes, protocols can extend multiple other protocols:

class MyProtocol(NSCopying, NSMutableCopying):
    # method, property, etc. definitions go here

A custom protocol might not need to extend any other protocol at all. In this case, we need to explicitly tell Python to define an ObjCProtocol. Normally Python detects the metaclass automatically by examining the base classes, but in this case there are none, so we need to specify the metaclass manually.

class MyProtocol(metaclass=ObjCProtocol):
    # method, property, etc. definitions go here

Defining methods

rubicon.objc.api.objc_method(py_method)

Exposes the decorated method as an Objective-C instance method in a custom class or protocol.

In a custom Objective-C class, decorating a method with @objc_method makes it available to Objective-C: a corresponding Objective-C method is created in the new Objective-C class, whose implementation calls the decorated Python method. The Python method receives all arguments (including self) from the Objective-C method call, and its return value is passed back to Objective-C.

In a custom Objective-C protocol, the behavior is similar, but the method body is ignored, since Objective-C protocol methods have no implementations. By convention, the method body in this case should be empty (pass). (Since the method is never called, you could put any other code there as well, but doing so is misleading and discouraged.)

rubicon.objc.api.objc_classmethod(py_method)

Exposes the decorated method as an Objective-C class method in a custom class or protocol.

This decorator behaves exactly like @objc_method, except that the decorated method becomes a class method, so it is exposed on the Objective-C class rather than its instances.

Method naming

The name of a Python-defined Objective-C method is same as the Python method’s name, but with all underscores (_) replaced with colons (:) — for example, initWithWidth_height_ becomes initWithWidth:height:.

Warning

The Objective-C language imposes certain requirements on the usage of colons in method names: a method’s name must contain exactly as many colons as the method has arguments (excluding the implicit self and _cmd parameters), and the name of a method with arguments must end with a colon. For example, a method called init takes no arguments, initWithSize: takes a single argument, initWithWidth:height: takes two, etc. initWithSize:spam is an invalid method name.

These requirements are not enforced by the Objective-C runtime, but methods that do not follow them cannot easily be used from regular Objective-C code.

In addition, although the Objective-C language allows method names with multiple consecutive colons or a colon at the start of the name, such names are considered bad style and never used in practice. For example, spam::, :ham:, and : are unusual, but valid method names.

Future versions of Rubicon may warn about or disallow such nonstandard method names.

Parameter and return types

The argument and return types of a Python-created Objective-C method are determined based on the Python method’s type annotations. The annotations may contain any ctypes type, as well as any of the Python types accepted by ctype_for_type(). If a parameter or the return type is not specified, it defaults to ObjCInstance. The self parameter is special-cased — its type is always ObjCInstance, even if annotated otherwise. To annotate a method as returning void, set its return type to None.

Before being passed to the Python method, any object parameters (objc_id) are automatically converted to ObjCInstance. If the method returns an Objective-C object, it is converted using ns_from_py() before being returned to Objective-C. These automatic conversions can be disabled by using objc_rawmethod() instead of objc_method().

The implicit _cmd parameter is not passed to the Python method, as it is normally redundant and not needed. If needed, the _cmd parameter can be accessed by using objc_rawmethod() instead of objc_method().

rubicon.objc.api.objc_rawmethod(py_method)

Exposes the decorated method as an Objective-C instance method in a custom class, with fewer convenience features than objc_method().

This decorator behaves similarly to @objc_method. However, unlike with objc_method(), no automatic conversions are performed (aside from those by ctypes). This means that all parameter and return types must be provided as ctypes types (no ctype_for_type() conversion is performed), all arguments are passed in their raw form as received from ctypes, and the return value must be understood by ctypes.

In addition, the implicit _cmd parameter is exposed to the Python method, which is not the case when using objc_method(). This means that the decorated Python method must always have an additional _cmd parameter after self; if it is missing, there will be errors at runtime due to mismatched argument counts. Like self, _cmd never needs to be annotated, and any annotations on it are ignored.

Defining properties and ivars

rubicon.objc.api.objc_property(vartype=<class 'rubicon.objc.runtime.objc_id'>, weak=False)

Defines a property in a custom Objective-C class or protocol.

This class should be called in the body of an Objective-C subclass or protocol, for example:

class MySubclass(NSObject):
    counter = objc_property(NSInteger)

The property type may be any ctypes type, as well as any of the Python types accepted by ctype_for_type().

Defining a property automatically defines a corresponding getter and setter. Following standard Objective-C naming conventions, for a property name the getter is called name and the setter is called setName:.

In a custom Objective-C class, implementations for the getter and setter are also generated, which store the property’s value in an ivar called _name. If the property has an object type, the generated setter keeps the stored object retained, and releases it when it is replaced.

In a custom Objective-C protocol, only the metadata for the property is generated.

If weak is True, the property will be created as a weak property. When assigning an object to it, the reference count of the object will not be increased. When the object is deallocated, the property value is set to None. Weak properties are only supported for Objective-C or Python object types.

rubicon.objc.api.objc_ivar(vartype)

Defines an ivar in a custom Objective-C class.

If you want to store additional data on a custom Objective-C class, it is recommended to use properties (objc_property()) instead of ivars. Properties are a more modern and high-level Objective-C feature, which automatically deal with reference counting for objects, and creation of getters and setters.

The ivar type may be any ctypes type.

Unlike properties, the contents of an ivar cannot be accessed or modified using Python attribute syntax. Instead, the get_ivar() and set_ivar() functions need to be used.

rubicon.objc.api.get_ivar(obj, varname, weak=False)

Get the value of obj’s ivar named varname.

The returned object is a ctypes data object.

For non-object types (everything except objc_id and subclasses), the returned data object is backed by the ivar’s actual memory. This means that the data object is only usable as long as the “owner” object is alive, and writes to it will directly change the ivar’s value.

For object types, the returned data object is independent of the ivar’s memory. This is because object ivars may be weak, and thus cannot always be accessed directly by their address.

rubicon.objc.api.set_ivar(obj, varname, value, weak=False)

Set obj’s ivar varname to value. If weak is True, only a weak reference to the value is stored.

value must be a ctypes data object whose type matches that of the ivar.

Objective-C blocks

Blocks are the Objective-C equivalent of function objects, so Rubicon provides ways to call Objective-C blocks from Python and to pass Python callables to Objective-C as blocks.

Automatic conversion

If an Objective-C method returns a block (according to its type encoding), Rubicon will convert the return value to a special ObjCInstance that can be called in Python:

block = an_objc_instance.methodReturningABlock()
res = block(arg, ...)

Similarly, if an Objective-C method has a parameter that expects a block, you can pass in a Python callable object, and it will be converted to an Objective-C block. In this case, the callable object needs to have parameter and return type annotations, so that Rubicon can expose this type information to the Objective-C runtime:

def result_handler(res: objc_id) -> None:
    print(ObjCInstance(res))

an_objc_instance.doSomethingWithResultHandler(result_handler)

If you are writing a custom Objective-C method (see Creating custom Objective-C classes and protocols), you can annotate parameter or return types using objc_block so that Rubicon converts them appropriately:

class AnObjCClass(NSObject):
    @objc_method
    def methodReturningABlock() -> objc_block:
        def the_block(arg: NSInteger) -> NSUInteger:
            return abs(arg)
        return the_block

    @objc_method
    def doSomethingWithResultHandler_(result_handler: objc_block) -> None:
        res = SomeClass.someMethod()
        result_handler(res)

Note

These automatic conversions are mostly equivalent to the manual conversions described in the next section. There are internal technical differences between automatic and manual conversions, but they are not noticeable to most users.

The internals of automatic conversion and objc_block handling may change in the future, so if you need more control over the block conversion process, you should use the manual conversions described in the next section.

Manual conversion

These classes are used to manually convert blocks to Python callables and vice versa. You may need to use them to perform these conversions outside of Objective-C method calls, or if you need more control over the block’s type signature.

class rubicon.objc.api.ObjCBlock(pointer[, return_type, *arg_types])

Python wrapper for an Objective-C block object.

This class is used to manually wrap an Objective-C block so that it can be called from Python. Usually Rubicon will do this automatically, if the block object was returned from an Objective-C method whose return type is declared to be a block type. If this automatic detection fails, for example if the method’s return type is generic id, Rubicon has no way to tell that the object in question is a block rather than a regular Objective-C object. In that case, the object needs to be manually wrapped using ObjCBlock.

The constructor takes a block object, which can be either an ObjCInstance, or a raw objc_id pointer.

Note

objc_block is also accepted, because it is a subclass of objc_id). Normally you do not need to make use of this, because in most cases Rubicon will automatically convert objc_blocks to a callable object.

In most cases, Rubicon can automatically determine the block’s return type and parameter types. If a block object doesn’t have return/parameter type information at runtime, Rubicon will raise an error when attempting to convert it. In that case, you need to explicitly pass the correct return type and parameter types to ObjCBlock using the restype and argtypes parameters.

__call__(*args)

Invoke the block object with the given arguments.

The arguments and return value are converted from/to Python objects according to the default ctypes rules, based on the block’s return and parameter types.

class rubicon.objc.api.Block(func[, restype, *argtypes])

A wrapper that exposes a Python callable object to Objective-C as a block.

Note

Block instances are currently not callable from Python, unlike ObjCBlock.

The constructor accepts any Python callable object.

If the callable has parameter and return type annotations, they are used as the block’s parameter and return types. This allows using Block as a decorator:

@Block
def the_block(arg: NSInteger) -> NSUInteger:
    return abs(arg)

For callables without type annotations, the parameter and return types need to be passed to the Block constructor in the restype and argtypes arguments:

the_block = Block(abs, NSUInteger, NSInteger)

Defining custom subclasses of ObjCInstance

The following functions can be used to register custom subclasses of ObjCInstance to be used when wrapping instances of a certain Objective-C class. This mechanism is for example used by Rubicon to provide Python-style operators and methods on standard Foundation classes, such as NSString and NSDictionary.

rubicon.objc.api.register_type_for_objcclass(pytype, objcclass)

Register a conversion from an Objective-C class to an ObjCInstance subclass.

After a call of this function, when Rubicon wraps an Objective-C object that is an instance of objcclass (or a subclass), the Python object will have the class pytype rather than ObjCInstance. See type_for_objcclass() for a full description of the lookup process.

Warning

This function should only be called if no instances of objcclass (or a subclass) have been wrapped by Rubicon yet. If the function is called later, it will not fully take effect: the types of existing instances do not change, and mappings for subclasses of objcclass are not updated.

rubicon.objc.api.for_objcclass(objcclass)

Decorator for registering a conversion from an Objective-C class to an ObjCInstance subclass.

This is equivalent to calling register_type_for_objcclass() on the decorated class.

rubicon.objc.api.type_for_objcclass(objcclass)

Look up the ObjCInstance subclass used to represent instances of the given Objective-C class in Python.

If the exact Objective-C class is not registered, each superclass is also checked, defaulting to ObjCInstance if none of the classes in the superclass chain is registered. Afterwards, all searched superclasses are registered for the ObjCInstance subclass that was found. (This speeds up future lookups, and ensures that previously computed mappings are not changed by unrelated registrations.)

This method is mainly intended for internal use by Rubicon, but is exposed in the public API for completeness.

rubicon.objc.api.unregister_type_for_objcclass(objcclass)

Unregister a conversion from an Objective-C class to an ObjCInstance subclass.

Warning

This function should only be called if no instances of objcclass (or a subclass) have been wrapped by Rubicon yet. If the function is called later, it will not fully take effect: the types of existing instances do not change, and mappings for subclasses of objcclass are not removed.

rubicon.objc.api.get_type_for_objcclass_map()

Get a copy of all currently registered ObjCInstance subclasses as a mapping.

Keys are Objective-C class addresses as ints.