{"id":4241,"library":"rubicon-objc","title":"Rubicon-ObjC","description":"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.","status":"active","version":"0.5.3","language":"en","source_language":"en","source_url":"https://github.com/beeware/rubicon-objc","tags":["Objective-C","bridge","iOS","macOS","BeeWare","ctypes","runtime"],"install":[{"cmd":"pip install rubicon-objc","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"note":"The primary class for wrapping existing Objective-C classes by name.","symbol":"ObjCClass","correct":"from rubicon.objc import ObjCClass"},{"note":"A common base class for defining new Objective-C classes in Python.","symbol":"NSObject","correct":"from rubicon.objc import NSObject"},{"note":"Used for explicitly working with Objective-C blocks (closures).","symbol":"ObjCBlock","correct":"from rubicon.objc import ObjCBlock"},{"note":"Python 3.14 deprecated custom event loop policies. Instantiate `RubiconEventLoop()` directly instead of installing `EventLoopPolicy` or calling `asyncio.new_event_loop()` after setting a policy. This is the recommended approach for all Python versions since `rubicon-objc` v0.5.1.","wrong":"from rubicon.objc.eventloop import EventLoopPolicy","symbol":"RubiconEventLoop","correct":"from rubicon.objc import RubiconEventLoop"},{"note":"Since v0.4.7, `objc_id` and `objc_block` are exposed directly under `rubicon.objc` namespace.","wrong":"from rubicon.objc.runtime import objc_id","symbol":"objc_id","correct":"from rubicon.objc import objc_id"}],"quickstart":{"code":"from rubicon.objc import ObjCClass, NSObject\nimport asyncio\n\n# Access an Objective-C class (e.g., NSURL from Foundation framework)\nNSURL = ObjCClass(\"NSURL\")\n\n# Create an instance using a static constructor method.\n# Objective-C methods with ':' are mapped to Python keyword arguments or replaced with '_' in method name.\n# E.g., Objective-C's +URLWithString: becomes .URLWithString_() or .URLWithString(url_string).\nbase_url = NSURL.URLWithString_(\"https://beeware.org/\")\nprint(f\"Base URL: {base_url}\")\n\n# Call another method with multiple arguments using keyword arguments\nfull_url = NSURL.URLWithString_relativeToURL_(\"contributing/\", relativeToURL=base_url)\nprint(f\"Full URL: {full_url}\")\n\n# Access Objective-C properties using Python attribute syntax\nprint(f\"Full URL scheme: {full_url.scheme}\")\n\n# --- Defining a new Objective-C class in Python ---\n# In interactive environments (like Pythonista) or when re-running code, \n# Objective-C class redefinition can cause errors. auto_rename avoids this.\nObjCClass.auto_rename = True # Set globally or pass auto_rename=True to ObjCClass() constructor\n\nclass MyPythonDelegate(NSObject):\n    # Initialize the Objective-C object. Must call super().init()\n    def init(self):\n        self = super().init()\n        if self:\n            print(\"MyPythonDelegate initialized!\")\n        return self\n\n    # Define an Objective-C method (e.g., a delegate callback)\n    # Argument types should generally be annotated for clarity and correctness.\n    def myDelegateMethod_withValue_(self, sender: 'id', value: int):\n        print(f\"Delegate method called by {sender} with value: {value}\")\n        return None # Objective-C methods often return `void` or `id` (None for Python)\n\n# Instantiate the Python-defined Objective-C class\ndelegate_instance = MyPythonDelegate.alloc().init()\n\n# Example of calling its method (simulating an Objective-C call)\ndelegate_instance.myDelegateMethod_withValue_(NSObject.alloc().init(), 42)\n","lang":"python","description":"This quickstart demonstrates how to access existing Objective-C classes like `NSURL`, create instances, call methods using Pythonic syntax (handling Objective-C selectors with colons), and access properties. It also shows how to define a new Objective-C class in Python by subclassing `NSObject`, including important considerations for interactive development environments regarding class redefinition."},"warnings":[{"fix":"Upgrade your Python environment to 3.10 or higher, or pin `rubicon-objc<0.5.3`.","message":"Python 3.9 support was dropped in `rubicon-objc` v0.5.3. Ensure your environment uses Python 3.10 or newer.","severity":"breaking","affected_versions":">=0.5.3"},{"fix":"Instead of `asyncio.set_event_loop_policy(EventLoopPolicy())` and `asyncio.new_event_loop()`, directly instantiate and use `loop = RubiconEventLoop()` for your event loop. This change is backward compatible for older Python versions too.","message":"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.","severity":"breaking","affected_versions":">=0.5.1"},{"fix":"Familiarize yourself with `rubicon-objc`'s selector translation rules. When in doubt, check the method signature in Objective-C documentation and experiment with both `_` and keyword argument styles.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Add `ObjCClass.auto_rename = True` at the top of your script or pass `auto_rename=True` as a keyword argument when defining Objective-C classes in Python.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Upgrade to `rubicon-objc` v0.5.0 or newer to benefit from automatic memory management. If on older versions, ensure correct manual retain/release calls, especially for objects returned by methods starting with 'alloc', 'new', 'copy', or 'mutableCopy'.","message":"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.","severity":"deprecated","affected_versions":"<0.5.0"},{"fix":"For explicit conversion of Objective-C return values to their Python equivalents, use `rubicon.objc.api.py_from_ns(obj)`.","message":"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.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}