Swift Tip: Using AppKit from the Command-line
In Swift, it's very easy to write a command-line app. As a simple example, you can paste the following into a file called wc.swift
:
while let line = readLine() {
print(line.split(separator: " ").count)
}
This will print out the number of words on each line. We can, for instance, use it on itself:
$ cat wc.swift | swift wc.swift
6
3
1
On the Mac, we're not limited to console input and output. We can also run an entire Mac app directly from the command-line. When we import AppKit, we can access the shared application, set a delegate, and run the application.
For example, let's save the following code into a file called spell.swift
:
import AppKit
let app = NSApplication.shared
class AppDelegate: NSObject, NSApplicationDelegate {
let window = NSWindow(contentRect: NSMakeRect(200, 200, 400, 200),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered,
defer: false,
screen: nil)
func applicationDidFinishLaunching(_ notification: Notification) {
window.makeKeyAndOrderFront(nil)
let field = NSTextView(frame: window.contentView!.bounds)
field.backgroundColor = .white
field.isContinuousSpellCheckingEnabled = true
window.contentView?.addSubview(field)
DispatchQueue(label: "background").async {
while let str = readLine(strippingNewline: false) {
DispatchQueue.main.async {
field.textStorage?.append(NSAttributedString(string: str))
}
}
app.terminate(self)
}
}
}
let delegate = AppDelegate()
app.delegate = delegate
app.run()
From the terminal, we can now run swift spell.swift
, and the app will read lines from the standard input, adding them to a text field that has spell checking enabled. This particular example might be silly, but with all of AppKit at our disposal the possibilities are practically endless.
For instance, we could use the Open panel to prompt the user for a file:
// select.swift
import AppKit
func selectFile() -> URL? {
let dialog = NSOpenPanel()
dialog.allowedFileTypes = ["jpg", "png"]
guard dialog.runModal() == .OK else { return nil }
return dialog.url
}
print(selectFile()?.absoluteString ?? "")
Similarly, we could write scripts with a GUI for previewing images, processing images, finding a web page's URL using WKWebView
, and so on.
In other words, we can easily sprinkle some GUI elements onto our command-line scripts when it's more convenient than relying on the command-line alone.
If you'd like to learn more, Swift Talk Episode 22 shows you how to write simple command-line tools that leverage frameworks like Foundation and Cocoa.
To watch, become a subscriber. ๐