Search code examples
objective-cswiftapplescriptcocoa-scriptingnsappleeventdescriptor

Unable to unwrap NSAppleEventDescriptor in SWIFT


I'm having an Applescript which gives me a result. But I am unable to unwarp the value to String so i can use it.

var set: String = "set windowTile to \"\"\n"
var tell: String = "tell application \"System Events\"\n"
var setFrontApp: String = "set frontApp to first application process whose frontmost is true\n"
var setFrontAppName: String = "set frontAppName to name of frontApp\n"
var tellProcces: String = "tell process frontAppName\n"
var tellFirst: String = "tell (1st window whose value of attribute \"AXMain\" is true)\n"
var setWindowTitle: String = "set windowTitle to value of attribute \"AXTitle\"\n"
var endTellFirst: String = "end tell\n"
var endTellProcess: String = "end tell\n"
var endTell: String = "end tell"
var startAtLoginScript: NSAppleScript = NSAppleScript(source: set + tell + setFrontApp + setFrontAppName + tellProcces + tellFirst + setWindowTitle + endTellFirst + endTellProcess + endTell)     
var scriptResult:NSAppleEventDescriptor = startAtLoginScript.executeAndReturnError(errorInfo)!

NSLog ("%@",  scriptResult)

The NSLog looks like this:

2015-03-14 15:15:14.001 test[7315:161881] 
<NSAppleEventDescriptor:'utxt'("test.swift")>

The actual Result is a String "test.swift". How can I unwrap/parse this result?

I tried adding this:

var number:Int = 1
let result = scriptResult.descriptorAtIndex(number)

Also i tried using the method descriptorForKeyword(<#keyword: AEKeyword#>) but i do not know hot to set AEKeyword.


Solution

  • You can use if…let syntax to simultaneously check the result for nil and unwrap it if it has a value.

    descriptorAtIndex won’t get what you want because the descriptor doesn’t contain a utxt entry – it is a utxt entry (you can see this by printing out result.descriptorType which will give you the four-characted code for 'utxt'). So stringValue should get you the plain string value, but it’s an optional so you can unwrap in the same let.

    If you only want to output the data, println will do it without the timestamp etc. (in fact NSLog also logs an error to the console which you probably don’t want)

    import Foundation
    
    let script = "\n".join([
      "set windowTile to \"\"",
      "tell application \"System Events\"",
        "set frontApp to first application process whose frontmost is true",
        "set frontAppName to name of frontApp",
        "tell process frontAppName",
          "tell (1st window whose value of attribute \"AXMain\" is true)",
            "set windowTitle to value of attribute \"AXTitle\"",
          "end tell",
        "end tell",
      "end tell",
    ])
    
    var errorInfo: NSDictionary?
    
    if let script = NSAppleScript(source: script),
       let result = script.executeAndReturnError(&errorInfo),
       let text = result.stringValue {
        println(text)
    }
    else if let error = errorInfo {
        println(error)
    }
    else {
        println("Unexpected error while executing script")
    }