Parmanoir

Crossing the WebKit bridge

UPDATE check out JSCocoa, a bridge from Javascript to Cocoa. It allows calling ObjC, C, using C structs, and definining your own classes. It's open source.

Unfortunately the WebKit bridge is not as full featured as RubyCocoa's. You can call ObjC methods, use strings, numbers and arrays, and that's it. No C methods or structs, no derivating JS objects from ObjC objects. Following Using Objective-C From JavaScript describes the possibilities, the one thing of note is that calls like [someObject someMethod:@"hello" withAnotherParam:@"world"] are translated as someObject.someMethod_withAnotherParam_('hello', 'world') .

What's of note

  • NSDictionary is useless. Returning [NSDictionary dictionaryWithObjectsAndKeys:@"someString", @"key", nil] will yield a very strange JS object. You can display it with document.write(hashFromObjC) and you'll get what you expect : { key : someString }, but that hash is not usable at all ! Trying hash['key'] or hash.key gives nothing, trying to loop over it with for (name in hash) … gives nothing either. On the other direction, passing a hash to ObjC wil yield a WebScriptObject, not a NSDictionary. So, hashes are out.
  • Retain count. Exposing an object with [windowScriptObject setValue:theObject forKey:@"theObject"]; retains the object. Each ObjC method returning an object retains it. If you don't 'cache' the object you got and always do objCobjectExposedToJS.getObject().doStuff(), the retain count of the object returned by getObject will be incremented each time you call it. BUT getting an object in an array doesn't retain it.
  • No manual garbage collection start method. Internet explorer had GC.collect(), useful to check for memory leaks. In Safari, there's a WebCoreStatistics that's handling quite a lot of stuff, including garbage collection. Add a method collect to your JS-exposed object that calls [objc_getClass("WebCoreStatistics") garbageCollectJavaScriptObjects] and you'll get a manual way to start JS collection. Check WebCoreStatistics.mm in the WebKit source for a list of its methods, including interesting stuff like javaScriptObjectsCount.
  • Crossing stuff like NSPoint will have to be done with arrays.
#define NSPointToJS(p) [NSArray arrayWithObjects:[NSNumber numberWithFloat:p.x], [NSNumber numberWithFloat:p.y], nil]
#define NSPointFromJS(d) NSMakePoint([[d objectAtIndex:0] floatValue], [[d objectAtIndex:1] floatValue])

Pieter
2008 10 31

Does passing arrays from JS to ObjC work for you? If I try it, I get a WebScriptObject instead of an NSArray (even though the docs say it's supposed to work).

Patrick Geiller
2008 11 01

You do get a WebScriptObject, but you can call objectAtIndex on it.


Follow me on Twitter
Planet Cocoa
Cocoa.fr

2011 02 22Distance field
2010 07 202Binding through NSApp
2010 05 122Forwarding invocations
2010 02 272Core Image black fringes
2010 02 21Quickest Way to Shell
2010 02 08Who's calling ?
2009 09 2138 ways to use Blocks in Snow Leopard
2009 08 182Bracket Mess
2009 08 124Taming JavascriptCore within and without WebView
2009 04 15Debugging with Activity Monitor
2009 03 25How Core Image Color Tracking works
2009 03 1510Custom NSThemeFrame
2009 03 10Which framework is running ?
2009 03 074CoreUI can paint pretty big
2009 02 18Localization with functions
2009 01 30Did you forget to nest alloc and init?
2009 01 16JSCocoa on the iPhone
2009 01 11Mixing WebView and JavascriptCore
2009 01 09Badge overflow
2009 01 09Find your Garbage Collection leaks with Instruments

Powered by MediaWiki