4

In order to support binary data exchange in my scriptable Mac app, I like to make it possible to receive and deliver data as NSData, using the AS-ObjC bridge, if that's possible.

For instance, I like to make this code possible in AppleScript:

use framework "Foundation"

set theData to current application's NSData's dataWithContentsOfFile:"/some/binary/file"

tell application "MyApp"
    set raw value to theData
end tell

The sdef contains a value-type and property for this:

<suite name="My Suite" code="Demo">
    <value-type name="ObjCNSData" code="NSDa">
        <cocoa class="NSData"/>
    </value-type>
    <class name="application" code="capp">
        <property name="raw data" code="rawD" type="ObjCNSData">
            <cocoa key="rawData"/>
        </property>

I then implement the conversion handler as an extension to NSData, similarly to how the Sketch example converts NSColor to the value-type "RGB Color":

@implementation NSData(DemoScripting)
+ (NSData *)scriptingObjCNSDataWithDescriptor:(NSAppleEventDescriptor *)desc {
    id res = [desc coerceToDescriptorType:'NSDa'];
    // -> res is NULL, which is not getting me any further
}

The desc's description is:

<NSAppleEventDescriptor: 'obj '{
  'form':'ID  ',
  'want':'ocid',
  'seld':'optr'($E0A8430080600000$),
  'from':null()
}>

Similarly, invoking [NSScriptObjectSpecifier _scriptingSpecifierWithDescriptor:descriptor] returns NULL as well.

So, how do I get to the actual NSData object inside my app code?

And how do I return a NSData object to the AppleScript?

2
  • NSData and AppleScript data are not interchangeable. But the type of the with data parameter is not necessarily binary data. You could add value-type entries in your sdef file to convert NSData to the AS type MyAppType expects. In your code theData represents clearly UTF8 encoded String. The NSAppleEventDescriptor returned from the make command contains a pointer ('optr') to the NSData instance. I'd recommend to ask the ASOC gurus Mark Alldritt from LateNightSoftware or Shane Stanley directly Commented Apr 26, 2019 at 12:42
  • So you mean I should evaludate the "optr" myself instead of looking for a framework function that'd do that for me? I can do that. But that still leaves the question of how to return a NSData object. Commented Apr 26, 2019 at 14:04

1 Answer 1

1

Shane Stanley did indeed know a way, and it does not even require extra code in my app - instead, it can all be done in AppleScript, with these two conversion functions:

use framework "Foundation"

set nsData1 to current application's NSData's dataWithContentsOfFile:"/etc/hosts"
set asData to my ASDataFromNSData(nsData1)
set nsData2 to my NSDataFromASData(asData)

on ASDataFromNSData(theData)
    set theCode to current application's NSHFSTypeCodeFromFileType("'rdat'")
    return (current application's NSAppleEventDescriptor's descriptorWithDescriptorType:theCode |data|:theData) as data
end ASDataFromNSData

on NSDataFromASData(asData)
    return (current application's NSArray's arrayWithObject:asData)'s firstObject()'s |data|()
end NSDataFromASData

It appears that rdat is a special AppleScript type for this purpose, with the framework automatically handling the conversion with NSData. I can't find that type declared in the AE.framework's headers, though.

I then still have to handle this rdat type explicitly in my app's code, though. But I won't need the value-type in the sdef, and can change the property to:

<property name="raw data" code="rawD" type="any">
    <cocoa key="rawData"/>
</property>

Returning data as rdat is similar. My -rawData method:

return [NSAppleEventDescriptor descriptorWithDescriptorType:'rdat' data:myNSData];

This only works if I declare the property type as "any", though. If I use type="rdat", Script Debugger shows the type as a dedicated raw data type, but then I get -10000 errors when trying to set or get the property in a script.

Sign up to request clarification or add additional context in comments.

4 Comments

There should be more logging in Xcode that may help you identify the cause of the problem. If there isn't, enable Cocoa Scripting debug logging. There is probably some attempt at conversion that is failing and you'll need to implement a method for that.
You can mark your own answer as the selected/"correct" answer, as it'll be useful for other users too (like myself).
@CJK Remind me tomorrow. SO let's me accept my own answers only after 2 days, so that others still have a chance to provide a better one. And then delete your comment (as I will mine) to reduce clutter :)
Thomas & CJK, tomorrow has come and gone! :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.