Thursday, January 27, 2011

Distributed Objects on OS X

I got a simple example with Distributed Objects working. This is supposed to be the standard way to communicate between processes. I tried it first with both the Server and the Client in PyObjC. Eventually I rewrote the Server in Objective-C and then it worked.

[UPDATE: Found a great working example (old, but from an Apple engineer here). ]

The output is:

> python 
<VendedObject: 0x10010cce0>
<objective-c class NSDistantObject at 0x7fff70a64868>

I'm not sure what the problem was but the error I got was

[OC_PythonString initWithBytes:length:encoding:]: unrecognized selector sent to instance 0x3635130


// gcc talk.m -o test -framework Foundation
#import <Foundation/Foundation.h>

@interface VendedObject:NSObject {}
-(NSString *) speak;

@implementation VendedObject

-(NSString *) speak {
return @"woof";

int main(){
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
VendedObject *obj;
obj = [[[VendedObject alloc ] init] autorelease];
NSLog(@"%@", [obj description]);

NSConnection *conn;
conn = [[[NSConnection alloc] init] autorelease];
[conn setRootObject:obj];
BOOL result;
result = [conn registerName:@"my_server"];
if (!result) {
NSLog(@"Failed to register Name");
else {
NSLog(@"%@", [conn description]);
[[NSRunLoop mainRunLoop] run];
[pool drain];
return 0;

Run with:

> ./test
2011-01-27 12:09:39.001 test[36995:903] <VendedObject: 0x10010cce0>
2011-01-27 12:09:39.005 test[36995:903] (** NSConnection 0x100112050 receivePort <NSMachPort: 0x100112530> sendPort <NSMachPort: 0x100112530> refCount 1 **)

You'll have to kill the process when you're done. If you have tried once already in Terminal, you will need to Quit Terminal and Re-launch. Otherwise registerName: will fail.


from Foundation import *

proxy_obj = NSConnection.rootProxyForConnectionWithRegisteredName_host_(
#"my_server", "osxserver.local")
"my_server", None)
if not proxy_obj:
print 'Did not get an object from the server.'
print proxy_obj.description()
print type(proxy_obj)
print proxy_obj.speak()

I also tried to connect to another machine on my local network, but I couldn't get that to work either. The proxy_obj was nil/None.


Niu & Niu said...
This comment has been removed by the author.
C. Minos Niu said...

My study is in computational neuroscience. I'm working heavily on Python to deal with data, interact with our signal acquisition devices. I've been looking for ways to visualize the Python-handled data on the Cocoa platform. It seemed that Apple has little interest in it ever since 2009.

Your series of posts are great, hope to keep going with you on Python+Cocoa programming

telliott99 said...

Thanks for reading! I appreciate the encouragement.

Re Python on OS X: Of course Python itself is great on the Mac, and if you get matplotlib installed it makes really nice graphics. The future of PyObjC seems more uncertain. Still, that is working right now, and it provides a mostly painless path to development. Once you've got a design worked out, you can always rewrite it in Objective-C later.

علی در رویا said...

Howdy! I was trying to add an NSString argument to your prototype and am getting NSInvalidArgumentException failures.

I modified the server functions to accept NSString* as argument and call the function like this:


Any idea ?

telliott99 said...

I have to look into this. The client is supposed to negotiate with the proxy about what protocol they follow. And I don't have PyObjC installed any more.

I changed the talk class slightly, and rewrote the listener in Objective C. It seems to work, sort of. The code is here:

telliott99 said...

I was able to silence the warning by adding this to the return type of speak: -(inout NSString *). I was also able to add a parameter to the method and it works fine, except that the warning comes back and I haven't been able to silence it. There is some discussion here: