Running Swift from the command line

A few months back I wrote a fairly simple Swift command line app in Xcode. The app did some Core Graphics drawing and saved the results to a PDF in the user’s Documents directory. The project consisted of a single main.swift file. Running it from with Xcode worked great. The PDF was created and saved to disk.

Today, I tried running either the uncompiled main.swift file or the compiled command line app from the command line with the following results:

$ ./main.swift
./main.swift:102:27: error: 'init(CGContext:flipped:)' is only available on OS X 10.10 or newer
    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:false)
                          ^
./main.swift:102:27: note: add 'if #available' version check
    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:false)
                          ^
./main.swift:102:27: note: add @available attribute to enclosing global function
    let graphicsContext = NSGraphicsContext(CGContext: context!, flipped:false)
                          ^

Even though I’m running this on OS X 10.11 and even though this runs just fine from within Xcode, it’s complaining that I’m trying to use a bit of API that might not be available.

Solution #1

The app kicks off by calling a function called drawPDF(). It’s within that function that the call to NSGraphicsContext(CGContext: context!, flipped:false) is made. So the first way to get this to work is to make sure the offending code isn’t executed on a pre-10.10 system. In this case, I’ll use a guard statement at the top of the function that will skip the entire function if the user isn’t on 10.10 or newer:

func drawPDF() {
    guard #available(OSX 10.10, *) else {return}
    // ... the rest of the function ...

This allows the file to be run from the command line, but then Xcode flags that line with a warning: Unnecessary check for 'OSX'; minimum deployment target ensures guard will always be true. Yes, my Xcode project requires at least OS X 10.11, so Xcode is pointing out that I don’t need this check because we are guaranteed to always be running at OS 10.11. That’s a little annoying and I’m sure there’s a project setting to silence this kind of warning. But I’m not a big fan of silencing warnings. So this is an imperfect solution.

Solution #2

Add a @available attribute on the function that makes the potentially problematic API:

@available (OSX 10.10, *)
func drawPDF() {
    // ... the rest of the function ...

This doesn’t quite work because running from the command line now complains that I’m calling drawPDF() and that function requires at least OS X 10.10. So I have to do an if #available check before calling it:

if #available(OSX 10.10, *) {
    drawPDF()
}

And with that, it works great at the command line, but I get another one of those warning from Xcode telling me that I’m doing an unnecessary #available check.

Conclusion

I’m not sure what the best/correct solution is. These both work but I don’t like the warnings in Xcode. ¯\_(ツ)_/¯