4
votes

I'm invoking a small AppleScript handler from within a larger Cocoa/Objective-C app (using the AppleScript-ObjC framework to call the AppleScript methods directly from the Objective-C code). I originally tried using Scripting Bridge, but that didn't work for me due to compatibility problems with the external app. The only purpose of the AppleScript is essentially to send a small string to the external app. This is the first time I've attempted to do something like this in order to control an external application, so please bear with me if I'm making an obvious mistake.

Occasionally, the AppleScript may encounter errors depending on the state of the external application, and I would like to handle those errors appropriately in my Objective-C code.

The way I'm doing this right now is that I have a try block in the AppleScript:

try
    -- Do stuff
    return the number 0
on error the error_message number the error_number
    return the error_number
end try

I return zero if the script finishes normally, and return the error number if it doesn't. Then in the Objective-C code, I test the return value and throw a "normal" exception in cases where there is an error, so that I can handle that in my regular exception-handling code.

This works, but is there a way to trap the AppleScript exception directly from the Objective-C code? When I run the code without the AppleScript try-error code in XCode, it seems that it hits my exception breakpoint before it returns from the AppleScript, but it never invokes the @catch block for NSException. Is there some way to catch that exception that is being hit somehow? I'm guessing the answer is no, but I wanted to check that there isn't some better way to do this than what I'm doing. Apple's documentation on AppleScript-ObjC is rather sparse, and mostly just discusses handling errors within AppleScript.

Update: So, I just tried playing around with the breakpoint setup a little bit, and it turns out that it's a C++ exception being sent from the AppleScript code, not an Objective-C one. That's why it wasn't being caught by the @catch block I was using. It seems that the AppleScript-ObjC mechanism uses exceptions for control flow/recoverable errors, and I had my breakpoint set up to break when they are thrown. So, I think it's probably best to just catch the errors in the AppleScript application, and return an error code as a string or integer to the Objective-C code.

1
I can't answer your question specifically, but I'll point out that in Objective-C/Cocoa, exceptions are meant to indicate truly exceptional conditions, typically due to programmer error rather than errors that can be safely recovered from. From the documentation: "The Cocoa frameworks are generally not exception-safe. The general pattern is that exceptions are reserved for programmer error only, and the program catching such an exception should quit soon afterwards."Andrew Madsen
That's a good point, although some of the errors that could be coming from the AppleScript could well be unrecoverable errors. The only reason I ask that is that invoking the AppleScript code DOES seem to raise an exception that hits my exception breakpoint even for minor, recoverable errors...but it's not a normal Cocoa NSException, from what I can tell. So I just want to know if I can catch that from my Objective-C code (as opposed to AppleScript) somehow.mnemia
Interesting. How have you setup your exception breakpoint? What does the stack trace look like when the breakpoint is tripped?Andrew Madsen
How are you're running the AppleScript in the code. And sending the string. I ask this because NSApplescript has the executeAndReturnError: method.markhunte
I'm using the AppleScript-ObjC (ASOC) framework to run it. (Apple has about 4 methods of running AppleScript events from Objective-C code). With ASOC, you can embed AppleScript code directly into your Objective-C program, and call methods implemented in AppleScript from Objective-C (although the process for setting this up leaves a little bit to be desired: you have to implement an NSObject category to tell Objective-C about the signature of the AppleScript methods, since there are no header files for them). I used this method because it seems better than using NSAppleScript with strings.mnemia

1 Answers

0
votes

AppleScript uses C++ exceptions to implement its own exceptions, but nothing else; you shouldn’t see them in code that completes successfully. If an AppleScript exception escapes to point of returning to Objective-C, the bridge actually swallows it -- you should get a log message, and a nil/zero/NO return value from the bridged method. The upshot of all this is that you’re already doing the right thing: trap the error in AppleScript and return something that your Objective-C code can detect.

As a side note, AppleScriptObjC is mainly intended for developers writing applications primarily or entirely in AppleScript. If you’re writing a primarily Objective-C application with a few bits that control other applications via scripting, consider using ScriptingBridge instead.