appscript

AppleScript-ObjC

AppleScript-based "classes" may be used directly from Objective-C and other languages via the AppleScript-ObjC bridge (10.6+).

Calling from Swift

Sample Project

Calling from Objective-C

AppleScript-ObjC allows you to use ObjC for all your general programming stuff, and only call into AppleScript via the AppleScript-ObjC bridge for the IPC stuff.

From the POV of your ObjC code, your AppleScript-based ASOC 'classes' are more or less indistinguishable from regular ObjC classes. It requires a bit of fiddling to set up, and you'll pay a bit of a toll when crossing the bridge, but given the crippled, unreliable nature of the alternatives, it's the least horrid of the supported options for anything non-trivial.

Assuming you've already got an existing ObjC-based project, here's how to add an ASOC-based class to it:

In Targets > APPNAME > Build Phases > Link Binary With Libraries, add AppleScriptObjC.framework.

In Supporting Files > main.m, add the import and load lines as shown:

#import <Cocoa/Cocoa.h>
#import <AppleScriptObjC/AppleScriptObjC.h>

int main(int argc, const char * argv[]) {
   [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
   return NSApplicationMain(argc, argv);
}

To define an ASOC-based class named MyASClass that's callable from ObjC, create a MyASClass.h interface file that declares its public methods:

// MyASClass.h

#import <Cocoa/Cocoa.h>

@interface MyASClass : NSObject

// Note: C primitives are only automatically bridged when calling from AS into ObjC.
// AS methods with boolean/integer/real parameters/results must declare NSNumber*:

- (NSNumber *)square:(NSNumber *)aNumber;

@end

along with a MyASClass.applescript file containing its implementation:

-- MyASClass.applescript

script MyASClass

   property parent : class "NSObject"

   on square_(aNumber)
	   return aNumber ^ 2
   end square_

end script

Because the MyASClass class doesn't have an ObjC implementation, the linker can't link your ObjC code to it at build-time. Instead, use NSClassFromString() to look up the class object at run-time:

#import "MyASClass.h"

...

MyASClass *stuff = [[NSClassFromString(@"MyASClass") alloc] init];

Otherwise it's pretty much indistinguishable from a native ObjC class in normal use:

NSNumber *result = [stuff square: @3];
NSLog(@"Result: %@", result);

Calling from Python

As of 10.10, AppleScript can use Cocoa frameworks in any Script Editor-based script. This makes it easy for Python and other languages that have Objective-C bridges to call AppleScript directly, without having to package everything as an Xcode app.

Stick one or more compiled .scpt files containing AppleScript-ObjC "classes" into a folder, e.g.:

use framework "Foundation"
use scripting additions

script MyASClass
   property parent : class "NSObject"
   --
   on test()
      activate
      display dialog "Hello from AppleScript!"
   end test
end script

then just use it from Python like this:

from Foundation import NSBundle, NSClassFromString
import AppleScriptObjC

NSBundle.alloc().initWithPath_(FOLDERPATH).loadAppleScriptObjectiveCScripts()

MyASClass = NSClassFromString(u"MyASClass") # get the ASOC class...
MyASClass.alloc().init().test() # ...then instantiate and call it