Rubicon-ObjC
Rubicon-ObjC is a robust bridge between the Python and Objective-C runtime environments, enabling Python code to instantiate, invoke methods on, and subclass Objective-C classes. It's a fundamental component of the BeeWare suite for building native applications with Python. The library is actively maintained, with its current version being 0.5.3, and follows a regular release cadence to support new Python versions and fix bugs.
Warnings
- breaking Python 3.9 support was dropped in `rubicon-objc` v0.5.3. Ensure your environment uses Python 3.10 or newer.
- breaking Starting with Python 3.14, custom `asyncio` event loop policies were deprecated. `rubicon-objc` v0.5.1 introduced `RubiconEventLoop()` as the preferred way to integrate with asyncio, replacing the older `EventLoopPolicy` mechanism.
- gotcha Objective-C method selectors containing colons (`:`) are translated into Python method names using either underscores (`_`) or keyword arguments. For example, `+URLWithString:relativeToURL:` can be called as `URLWithString_relativeToURL_('...', relativeToURL=...)` or sometimes `URLWithString('...', relativeToURL='...')` depending on the method signature. The keyword argument style is generally more Pythonic.
- gotcha In environments where the Objective-C runtime persists (e.g., Pythonista, or repeatedly running scripts in a long-lived process), redefining an Objective-C class with the same name will cause an error. To mitigate this, set `ObjCClass.auto_rename = True` globally or pass `auto_rename=True` when defining your `ObjCClass` subclasses. This appends a unique suffix to the class name in the runtime.
- deprecated Prior to v0.5.0, developers often needed to manually manage memory of Objective-C objects using `retain`, `release`, or `autorelease` calls from Python. Since v0.5.0, `rubicon-objc` automatically retains Objective-C objects when wrapped and autoreleases them on Python garbage collection, greatly simplifying memory management.
- gotcha While Rubicon-ObjC automatically converts basic Python types (like `str` to `NSString`, `bytes` to `NSData`) when passed as arguments, conversion of Objective-C return types back to native Python types (e.g., `NSString` to `str`) is not always automatic. You might need to explicitly use `py_from_ns()` for full Pythonic object conversion.
Install
-
pip install rubicon-objc
Imports
- ObjCClass
from rubicon.objc import ObjCClass
- NSObject
from rubicon.objc import NSObject
- ObjCBlock
from rubicon.objc import ObjCBlock
- RubiconEventLoop
from rubicon.objc import RubiconEventLoop
- objc_id
from rubicon.objc import objc_id
Quickstart
from rubicon.objc import ObjCClass, NSObject
import asyncio
# Access an Objective-C class (e.g., NSURL from Foundation framework)
NSURL = ObjCClass("NSURL")
# Create an instance using a static constructor method.
# Objective-C methods with ':' are mapped to Python keyword arguments or replaced with '_' in method name.
# E.g., Objective-C's +URLWithString: becomes .URLWithString_() or .URLWithString(url_string).
base_url = NSURL.URLWithString_("https://beeware.org/")
print(f"Base URL: {base_url}")
# Call another method with multiple arguments using keyword arguments
full_url = NSURL.URLWithString_relativeToURL_("contributing/", relativeToURL=base_url)
print(f"Full URL: {full_url}")
# Access Objective-C properties using Python attribute syntax
print(f"Full URL scheme: {full_url.scheme}")
# --- Defining a new Objective-C class in Python ---
# In interactive environments (like Pythonista) or when re-running code,
# Objective-C class redefinition can cause errors. auto_rename avoids this.
ObjCClass.auto_rename = True # Set globally or pass auto_rename=True to ObjCClass() constructor
class MyPythonDelegate(NSObject):
# Initialize the Objective-C object. Must call super().init()
def init(self):
self = super().init()
if self:
print("MyPythonDelegate initialized!")
return self
# Define an Objective-C method (e.g., a delegate callback)
# Argument types should generally be annotated for clarity and correctness.
def myDelegateMethod_withValue_(self, sender: 'id', value: int):
print(f"Delegate method called by {sender} with value: {value}")
return None # Objective-C methods often return `void` or `id` (None for Python)
# Instantiate the Python-defined Objective-C class
delegate_instance = MyPythonDelegate.alloc().init()
# Example of calling its method (simulating an Objective-C call)
delegate_instance.myDelegateMethod_withValue_(NSObject.alloc().init(), 42)