0

tldr: Changing the "Optimize for Speed" Swift Compiler setting from "No Optimization [-Onone]" to "Optimize for Speed [-O]" causes a string typecast to fail

Background

I am using a function from this StackOverflow answer in a program that I am making. It finds the url of an open TextEdit document

Problem

When I try to run my program with optimization turned on it crashes on this line

let filePath = result as! String

I am trying to find out how to get the String from the result variable.

The strange thing is that I can print the result variable to the console even if Optimize for Speed [-O] is on

How to reproduce

  1. Download the project here
  2. Ensure the app is not sandboxed
  3. Give the app accessibility permissions
  4. Open a TextEdit document and save it to disk
  5. Run app

Image of XCode with the No Optimization [-Onone] setting With Optimization Off Image of XCode with the Optimize for Speed [-O] setting on With Optimization ON

AppDelegate.swift Code

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        getOpenTextEditDocument()
    }

}

func getOpenTextEditDocument() -> URL? {
    // https://stackoverflow.com/questions/49076103/swift-get-file-path-of-currently-opened-document-in-another-application

    if AXIsProcessTrusted() == false {
        print("No Accesability Permissions")
        return nil
    }

    let textEditIdentifier = "com.apple.TextEdit"
    let TextEditApp : NSRunningApplication? = NSRunningApplication
        .runningApplications(withBundleIdentifier: textEditIdentifier).last as NSRunningApplication?

    if let pid = TextEditApp?.processIdentifier {

        var result = [AXUIElement]()
        var windowList: AnyObject? = nil // [AXUIElement]

        let appRef = AXUIElementCreateApplication(pid)

        if AXUIElementCopyAttributeValue(appRef, "AXWindows" as CFString, &windowList) == .success {
            result = windowList as! [AXUIElement]
        }

        var docRef: AnyObject? = nil
        guard let result_first = result.first else { return nil }
        if AXUIElementCopyAttributeValue(result_first, "AXDocument" as CFString, &docRef) == .success {
            let result = docRef as! AXUIElement

            let filePath = result as! String
            print("filePath = \(result)")
            let filePathURL = URL(string: filePath)
            return filePathURL
        }
    }
    return nil
}
Jonathan De Wet
  • 336
  • 1
  • 4
  • 12
  • `result` is an `AXUIElement`, so the statement `result as! String` is just going to forcibly cast an AXUIElement to a String object which is incorrect, hazardous, and unpredictable. If you need the string representation of an `AXUIElement` you'll need to convert it. – James Bucanek Dec 11 '19 at 00:51
  • Thanks, I did string(describing) instead and it worked – Jonathan De Wet Dec 26 '19 at 02:46

0 Answers0