views:

591

answers:

2

I'm developing a Python/ObjC application and I need to call some methods in my Python classes from ObjC. I've tried several stuffs with no success.

  • How can I call a Python method from Objective-C?
  • My Python classes are being instantiated in Interface Builder. How can I call a method from that instance?
+11  A: 

Use PyObjC.

It is included with Leopard & later.

>>> from Foundation import *
>>> a = NSArray.arrayWithObjects_("a", "b", "c", None)
>>> a
(
      a,
      b,
      c
)
>>> a[1]
'b'
>>> a.objectAtIndex_(1)
'b'
>>> type(a)
<objective-c class NSCFArray at 0x7fff708bc178>

It even works with iPython:

In [1]: from Foundation import *

In [2]: a = NSBundle.allFrameworks()

In [3]: ?a
Type:    NSCFArray
Base Class: <objective-c class NSCFArray at 0x1002adf40>

`

To call from Objective-C into Python, the easiest way is to:

  • declare an abstract superclass in Objective-C that contains the API you want to call

  • create stub implementations of the methods in the class's @implementation

  • subclass the class in Python and provide concrete implementations

  • create a factory method on the abstract superclass that creates concrete subclass instances

I.e.

@interface Abstract : NSObject
- (unsigned int) foo: (NSString *) aBar;
+ newConcrete;
@end

@implementation Abstract
- (unsigned int) foo: (NSString *) aBar { return 42; }
+ newConcrete { return [[NSClassFromString(@"MyConcrete" new] autorelease]; }
@end

.....

class Concrete(Abstract):
    def foo_(self, s): return s.length()

.....

x = [Abstract newFoo];
[x  foo: @"bar"];
bbum
A: 

The sample code above is great. I wish I had found this before. I have in the past used a sample of code from: http://code.google.com/p/python-application-stub/ , which seems to be from another talented developer, so I cannot say how it compares beyond both providing great insight and working.

Andrew