Calling Swift Methods from AppleScript

849 Views Asked by At

I am trying to write an AppleScript that calls my Swift application to get a value. The method takes a string and needs to return another string.

Here is my .SDF file:

<suite name="My Suite" code="MySU" description="My AppleScript suite.">
    <class name="application" code="capp" description="An application's top level scripting object.">
        <cocoa class="NSApplication"/>
        <element type="my types" access="r">
            <cocoa key="types"/>
        </element>
    </class>

    <command name="my command" code="MyCOMMND" description="My Command">
        <parameter name="with" code="MyPR" description="my Parameter" type="text">   
            <cocoa key="myParameter"/>
        </parameter>
        <result type="text" description="the return value"/>

        <cocoa method="myCommand:"/>
    </command>
</suite>

The corresponding Swift code is fairly simple:

func myCommand(_ command: NSScriptCommand) -> String
{
    if let myParameter = command.evaluatedArguments?["myParameter"] as? String
    {
        return "Hello World!"
    }
    else
    {
        return "Nothing happening here. Move on."
    }
}

and finally my AppleScript is here:

tell application "MyApp"
    set r to my command with "Hello"
end tell

When I execute the AppleScript it recognises my command, but it does not call the Swift code that I've tried to associate with it. Neither Xcode or AppleScript report a problem. Have I misses something out or put my code in the wrong place?

1

There are 1 best solutions below

1
On BEST ANSWER

For this sort of scripting I would recommend a command-first (aka verb-first) approach rather than the object-first approach you are attempting. Your sdef would look like this (replacing "MyProject" with the name of your project, i.e. your application's Swift module name):

<dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
<suite name="My Suite" code="MySU" description="My AppleScript suite.">

    <command name="my command" code="MySUCMND" description="My Command">
        <cocoa class="MyProject.MyCommand"/>
        <parameter name="with" code="MyPR" description="my Parameter" type="text">   
            <cocoa key="myParameter"/>
        </parameter>
        <result type="text" description="the return value"/>
    </command>

</suite>
</dictionary>

The MyCommand class should look like this:

class MyCommand : NSScriptCommand {

    override func performDefaultImplementation() -> Any? {
        if let _ = self.evaluatedArguments?["myParameter"] as? String
        {
            return "Hello World!"
        }
        else
        {
            return "Nothing happening here. Move on."
        }

    }
}

The "ModuleName.ClassName" sdef tip comes from Swift NSScriptCommand performDefaultImplementation