Your first bridge#
In this example, we’re going to use Rubicon to access the Objective-C
Foundation library, and the NSURL
class in that library. NSURL
is the
class used to represent and manipulate URLs.
This tutorial assumes you’ve set up your environment as described in the Getting started guide.
Accessing NSURL#
Start Python, and get a reference to an Objective-C class. In this example,
we’re going to use the NSURL
class, Objective-C’s representation of URLs:
>>> from rubicon.objc import ObjCClass
>>> NSURL = ObjCClass("NSURL")
This gives us an NSURL
class in Python which is transparently bridged to
the NSURL
class in the Objective-C runtime. Any method or property
described in Apple’s documentation on NSURL
can be accessed over this bridge.
Let’s create an instance of an NSURL
object. The NSURL
documentation
describes a static constructor +URLWithString:
; we can invoke this
constructor as:
>>> base = NSURL.URLWithString("https://beeware.org/")
That is, the name of the method in Python is identical to the method in
Objective-C. The first argument is declared as being an NSString *
; Rubicon
converts the Python str
into an NSString
instance as part of
invoking the method.
NSURL
has another static constructor: +URLWithString:relativeToURL:
. We
can also invoke this constructor:
>>> full = NSURL.URLWithString("contributing/", relativeToURL=base)
The second argument (relativeToURL
) is accessed as a keyword argument. This
argument is declared as being of type NSURL *
; since base
is an
instance of NSURL
, Rubicon can pass through this instance.
Sometimes, an Objective-C method definition will use the same keyword argument name twice. This is legal in Objective-C, but not in Python, as you can’t repeat a keyword argument in a method call. In this case, you can use a “long form” of the method to explicitly invoke a descriptor by replacing colons with underscores:
>>> base = NSURL.URLWithString_("https://beeware.org/")
>>> full = NSURL.URLWithString_relativeToURL_("contributing", base)
Instance methods#
So far, we’ve been using the +URLWithString:
static constructor. However,
NSURL
also provides an initializer method -initWithString:
. To use this
method, you first have to instruct the Objective-C runtime to allocate memory
for the instance, then invoke the initializer:
>>> base = NSURL.alloc().initWithString("https://beeware.org/")
Now that you have an instance of NSURL
, you’ll want to manipulate it.
NSURL
describes an absoluteURL
property; this property can be accessed
as a Python attribute:
>>> absolute = full.absoluteURL
You can also invoke methods on the instance:
>>> longer = absolute.URLByAppendingPathComponent('how/first-time/')
If you want to output an object at the console, you can use the Objective-C
property description
, or for debugging output, debugDescription
:
>>> longer.description
'https://beeware.org/contributing/how/first-time/'
>>> longer.debugDescription
'https://beeware.org/contributing/how/first-time/>'
Internally, description
and debugDescription
are hooked up to their
Python equivalents, __str__()
and __repr__()
, respectively:
>>> str(absolute)
'https://beeware.org/contributing/how/first-time/'
>>> repr(absolute)
'<rubicon.objc.api.ObjCInstance 0x1114a3cf8: NSURL at 0x7fb2abdd0b20: https://beeware.org/contributing/>'
>>> print(absolute)
<rubicon.objc.api.ObjCInstance 0x1114a3cf8: NSURL at 0x7fb2abdd0b20: https://beeware.org/contributing/>
Time to take over the world!#
You now have access to any method, on any class, in any library, in the entire macOS or iOS ecosystem! If you can invoke something in Objective-C, you can invoke it in Python - all you need to do is:
load the library with ctypes;
register the classes you want to use; and
Use those classes as if they were written in Python.
Next steps#
The next step is to write your own classes, and expose them into the Objective-C runtime. That’s the subject of the next tutorial.