Source

pyobjc-docs / pyobjc-core / Doc / advanced / blocks.rst

Blocks

Introduction

Objective-C has the concept of blocks, which are basically anonymous inline functions. They are sometimes known as closures Their syntax is like this:

^{ printf("x is %d\n", 42); }

This is a literal for a block that takes no arguments and prints a value when called.

Note

Blocks are only supported in PyObjC when it is compiled using an Objective-C compiler that also supports blocks.

Calling blocks from Python

The Python representation of an Objective-C block is a callable object. You can call the block in the same way as you call any other function object.

PyObjC manages the memory for blocks, it is not necessary to manage the reference counts of blocks in your code.

Limitations

It is not possible to call arbitrary blocks because PyObjC needs to store some additional metadata for a block. This means it is only possible to call blocks where the bridge knows the call signature, which means either:

  • the block was returned from a method for which we know the signature of returned blocks. PyObjC ships with metadata that covers all of Cocoa; [*] or
  • in your own code that defines methods that have block arguments or return values, you set the call signature of the block using the __block_signature__ attribute on the block.

When a block is stored in a Cocoa datastructure, such as an NSArray, and that is the only reference to the block, PyObjC will lose the additional information that is needed to call the block.

Implementing blocks in Python

It is very easy to use Objective-C methods that have a block as one of their arguments: just pass an arbitrary callable. PyObjC will automatically wrap your callable in the right low-level datastructure as it is sent across the bridge.

One of the side-effects of this is that the various storage classes that are defined in Objective-C for block-related variables are not relevant for Python users. Blocks behave just like regular functions.

[*]

This metadata is an extension to the "bridgesupport" format as defined by Apple.

If an argument or return value is a block, the metadata should contain an "block_pointer" attribute, with a value of "true". The element then has subelements describing the signature of block (excluding the implicit block parameter).

As an example:

<arg index="0" block_pointer="true">
   <retval type="v" />
   <arg type="@" />
   <arg type="B" />
</arg>

This metadata describes an argument that is a block of type (void(^)(id,BOOL).