NodObjC

The NodeJS ⇆ Objective-C Bridge

blockbridgesupportclasscoreexceptionffi-extendglobalidimpimportindexivarmethodselstructtypes

Index

NodObjC is the bridge between NodeJS and the Objective-C runtime and frameworks, making it possible to write native Cocoa applications (both GUI and command-line) using 100% NodeJS. Applications are written entirely in JavaScript and interpreted at runtime.

Getting Started

Every NodObjC application begins with requiring the NodObjC module. You can name the returned module variable anything you want, but the "canonical" name for it is $. This is mostly because you're going to be using the variable all over the place, and probably want to keep it short.

var $ = require('NodObjC')

The next step is to import() a desired "Framework" that is installed on the system. These frameworks are the APIs provided to Objective-C, which could be the default frameworks (provided by Apple) or 3rd party frameworks written by others (or you). The "Foundation" framework is the... well.. foundation of these APIs, providing the most basic and important classes like NSString and NSArray.

$.import('Foundation')

import() doesn't return anything, however it will throw an Error if anything goes wrong. What happens after the import call is that the $ variable now has a whole bunch of new properties attached to it, the exports from the imported framework. At this point, you can fully interact with these Objective-C classes, creating instances, subclassing, swizzling, etc.

A lot of core classes expect an NSAutoreleasePool instance on the stack, so the first Objective-C object instance you create is usually one of those.

var pool = $.NSAutoreleasePool('alloc')('init')

Pretty simple! You don't need to worry about the autorelease pool after this. Now, for an example, try creating an NSArray instance, well, an NSMutableArray technically, so we can also add an NSString to it.

var array = $.NSMutableArray('alloc')('init')

array('addObject', $('Hello World!'))

console.log(array)
// (
//     "Hello World!"
// )

So there's an NSArray instance with a count (Objective-C's version of Array#length) of 1, containing an NSString with the text "Hello World!". From here on out, you will need to refer to your Cocoa documentation for the rest of the available methods NSArray offers.

Message Sending Syntax

To send an Objective-C message to an Objective-C object using NodObjC, you have to invoke the object as a function, where the even number arguments make up the message name and the odd numbered arguments are the arguments to send to the object.

object('messageNameWithArg', someArg, 'andArg', anotherArg)

This sounds and probably looks strange at first, but this is the cleanest syntax while still being valid JS. It also maintains the "readabililty" of typical Objective-C method names.

Dynamic Object Introspection

Since NodObjC runs in an interpreted environment, it is actually very easy to dynamically inspect the defined methods, instance variables (ivars), implemented protocols, and more of any given Objective-C object (a.k.a. id instances).

Using the same array instance as before, you can retreive a list of the type of class, and it's subclasses, by calling the .ancestors() function.

array.ancestors()
// [ '__NSArrayM',
//   'NSMutableArray',
//   'NSArray',
//   'NSObject' ]

Also commonly of interest are the given methods an object responds to. Use the .methods() function for that.

array.methods()
// [ 'addObject:',
//   'copyWithZone:',
//   'count',
//   'dealloc',
//   'finalize',
//   'getObjects:range:',
//   'indexOfObjectIdenticalTo:',
//   'insertObject:atIndex:',
//   'objectAtIndex:',
//   'removeLastObject',
//   'removeObjectAtIndex:',
//   'replaceObjectAtIndex:withObject:' ]

More Docs

Check out the rest of the doc pages for some of the other important NodObjC pieces.

  • Block - How to use an Objective-C "block" function.
  • Class - Subclassing and adding methods at runtime.
  • Exception - NodObjC exceptions are JavaScript Error objects.
  • id - The wrapper class for every Objective-C object.
  • Import - Importing "Frameworks" into the process.
  • Ivars - Instance variable definitions.
  • Method - Method definitions and swizzling.
  • Structs - Using Structs and C functions in NodObjC.

This function accepts native JS types (String, Number, Date) and converts them to the proper Objective-C type (NSString, NSNumber, NSDate).

Often times, you will use this function to cast a JS String into an NSString for methods that accept NSStrings (since NodObjC doesn't automatically cast to NSStrings in those instances).

var jsString = 'a javascript String'
var nsString = $(jsString)

$.NSLog(nsString)
function $ (o) {
  var t = typeof o
  if (t == 'string') {
    return $.NSString('stringWithUTF8String', String(o))
  } else if (t == 'number') {
    return $.NSNumber('numberWithDouble', Number(o))
  } else if (isDate(o)) {
    return $.NSDate('dateWithTimeIntervalSince1970', o / 1000)
  }
  throw new Error('Unsupported object passed in to convert: ' + o)
}
Fork me on GitHub