DEV Community

Wiktor Wójcik
Wiktor Wójcik

Posted on • Originally published at 127.0.0.1 on

Some snippets of code for your Swift apps

Hi! While programming in Swift I have accumulated many code snippets. Some of them are mine and some of them come from the internet. Here I’m sharing 5 tiny quality-of-life snippets. Hopefully you will find them useful.

1. (Cocoa) Accessing NSWindow from NSViewController

extension NSViewController {
  var window: NSWindow? {
    for window in NSApp.windows {
      if window.contentViewController == self {
        return window
      }
    }
    return nil
  }
}

Enter fullscreen mode Exit fullscreen mode

This snippet adds a window variable to NSViewController. It requires the window to exist (eg. be in NSApp.windows, in most cases that will be true) and that there is only one window with the specified view controller. It will return the window with the view controller on which it is called.

2. Checking if path leads to a directory

extension FileManager {
  func isDirectory(path: String) -> Bool {
    var isDirectory: ObjCBool = false
    self.fileExists(atPath: path, isDirectory: &isDirectory)
    return isDirectory.boolValue
  }
}

Enter fullscreen mode Exit fullscreen mode

This is a simple wrapper around FileManager.fileExists() as an extension to FileManager that checks whether a path provided as a string leads to a directory.

3. Safely accessing an array

extension Array {
    subscript(safely index: Int) -> Element? {
        if index < self.endIndex && index >= 0 {
            return self[index]
        } else {
            return nil
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

This snippet adds a subscript to arrays. It checks whether index is within the array’s range then returns an element or nil depending on the check. You can use it like this:

let array = ["a", "b", "c"]
let value = array[safely: 2] // returns Optional("c")

Enter fullscreen mode Exit fullscreen mode

This might save you few lines of code for checking and force you to handle the edge case without crashing the app.

4. (SwiftUI) Web view wrapper

struct WebView: NSViewRepresentable {
    /// URL of current page. If changed, WebView will change it into the new URL.
    @Binding var url: URL

    private var onLoadStart: (WKWebView) -> ()
    private var onLoadFinish: (WKWebView) -> ()

  /// A WKWebView instance, which is used to render WebView, and which can be used to control it thanks to classes being passed by reference.
    private var wkWebView: WKWebView

  /// Accepts a binding to an URL, WKWebView instance, which can be used to control WebView and onLoadStart and onLoadFinish which will run when WebView starts or finishes loading a webpage.
    init(url: Binding<URL>, wkWebView: WKWebView = WKWebView(), onLoadStart: ((WKWebView) -> ())? = nil, onLoadFinish: ((WKWebView) -> ())? = nil) {
        self.wkWebView = wkWebView

        self.\_url = url

        if let onLoadStart = onLoadStart {
            self.onLoadStart = onLoadStart
        } else {
            self.onLoadStart = { \_ in }
        }

        if let onLoadFinish = onLoadFinish {
            self.onLoadFinish = onLoadFinish
        } else {
            self.onLoadFinish = { \_ in }
        }
    }

    func makeNSView(context: Context) -> WKWebView {
        wkWebView.navigationDelegate = context.coordinator
        wkWebView.load(URLRequest(url: url))

        return wkWebView
    }

    func updateNSView(\_ nsView: WKWebView, context: Context) {
        nsView.load(URLRequest(url: url))
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(onLoadStart: onLoadStart, onLoadFinish: onLoadFinish)
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        let onLoadStart: (WKWebView) -> ()
        let onLoadFinish: (WKWebView) -> ()

        init(onLoadStart: @escaping (WKWebView) -> (), onLoadFinish: @escaping (WKWebView) -> ()) {
            self.onLoadStart = onLoadStart
            self.onLoadFinish = onLoadFinish
        }

        func webView(\_ webView: WKWebView, didCommit navigation: WKNavigation!) {
            onLoadStart(webView)
        }

        func webView(\_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            onLoadFinish(webView)
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

This pretty lengthy snippet adds a simple SwiftUI wrapper around WKWebView (which needs to be imported). It only requires a binding to a url, which will be loaded. In more complex cases, you can pass onLoadStart and onLoadFinish handlers which will run when the web view starts and finishes loading and a WKWebView class instance. Since in Swift classes are passed by reference, you can use this instance in your view to control the web view (go back, forward, etc).

5. (Cocoa) Showing an alert

func showAlert(message: String, informative: String, buttons: [String] = [], completionHandler: @escaping (NSApplication.ModalResponse) -> () = { \_ in }) {
    DispatchQueue.main.async {
        let alert = NSAlert()

        alert.messageText = message
        alert.informativeText = informative

        buttons.forEach { alert.addButton(withTitle: $0) }

        let result = alert.runModal()
        completionHandler(result)
    }
}

Enter fullscreen mode Exit fullscreen mode

Once again, a wrapper. It wraps NSAlert in one function so that you don’t need to rewrite this code. It accepts a message and informative text which will be used on the alert. It also optionally accepts a list of button titles which will be added to the alert. It also runs asynchronously on the main thread, so it works even when run in another thread. Here I’d like to add that you can use NSAlert.accessoryView to create alerts with custom views, for example I did something like this:

func showChoicePrompt(message: String, informativeText: String, buttons: [String], completionHandler: @escaping (String?) -> Void) {
  let alert = NSAlert()

  alert.addButton(withTitle: "OK")
  alert.addButton(withTitle: "Cancel")

  alert.messageText = message
  alert.informativeText = informativeText

  let popUp = NSPopUpButton(frame: NSRect(x: 0, y: 0, width: 200, height: 24))
  popUp.addItems(withTitles: buttons)

  alert.accessoryView = popUp

  let response: NSApplication.ModalResponse = alert.runModal()

  if response == NSApplication.ModalResponse.alertFirstButtonReturn {
    completionHandler(popUp.selectedItem?.title)
  } else {
    completionHandler(nil)
  }
}

Enter fullscreen mode Exit fullscreen mode

which creates an alert with a pop up button for selecting a value.

As a sidenote, if you are dealing with many snippets of various types (like these ones), CodeMenu can help you organize, access and use their full potential.

Top comments (0)