DRb and NSDistributedNotificationCenter in RubyCocoa
I’m writing an OS X GUI test runner for Ruby. It’s coming along nicely, and I’ll have something to show fairly soon. In the meantime, I’m going to share some things I discovered in the process of writing it.
First, DRb (Distributed Ruby) doesn’t play well with Cocoa objects, due to incompatibilities between Ruby’s threading and Cocoa’s calling model. Sometimes it works; mostly, it results in segmentation faults.
Instead of DRb, I decided to use NSDistributedNotificationCenter, OS X’s own distributed notification system. I couldn’t find many examples of usage on the internet. There were zero server examples in Ruby, and one in Python. After a bit of trial and error, I got it working; hopefully Google and this page will save someone else the trouble.
Here’s some sample server code:
require 'osx/cocoa' include OSX class Server < NSObject def foo(notification) p notification_to_hash(notification) end def notification_to_hash(notification) nsd = notification.userInfo return nsd.allKeys.to_a.inject({}){ |hash, oc_key| hash[oc_key.to_s] = nsd.objectForKey(oc_key).to_s hash } end end server = Server.alloc.init center = NSDistributedNotificationCenter.defaultCenter center.addObserver_selector_name_object( server, "foo:", "My Notification", "com.example.MyApp" ) NSRunLoop.currentRunLoop.run
And the client:
require 'osx/cocoa' include OSX center = NSDistributedNotificationCenter.defaultCenter center.postNotificationName_object_userInfo_deliverImmediately( "My Notification", "com.example.MyApp", {"foo" => "bar", "baz" => 3}, true )
It’s generally quite simple, but it’s important that the server object be an instance of an NSObject (or one of its descendants). Plain Ruby objects cause bus errors.