diff --git a/Swift-Windows.md b/Swift-Windows.md
new file mode 100644
index 0000000..dae8e40
--- /dev/null
+++ b/Swift-Windows.md
@@ -0,0 +1,336 @@
+# Windows with Swift
+
+I'm just going to preface this by saying: holy hell, making windows work in Xcode and Swift is no small feat.
+
+This project features two windows: one that shows some basic information about the application, and another that shows the application's changelog, which will be loaded from a text file packaged with the application.
+
+## The "About" window
+
+
+
+### Building the window
+
+Hit **⌘+N** or right-click in the project navigator to add a new file to your project. Select **Window** in the **User Interface** section. Click **Next**, give your new file a name, and click **Create**. My file is named `InfoBox.xib`.
+
+Now we have an empty window we need to customize. You can resize the window using the handles on the corners and sides.
+
+We need to make a few customizations to the window's title bar.
+
+Make sure you've selected the **Window** (not the **View** under the window), and find the **Attribute Inspector** icon in the righthand pane of your Xcode window. You can also find this pane in the application menu under **View** > **Inspectors** > **Show Attribute Inspector**.
+
+Under **Title**, enter a display title (mine is "About LunaMac"), and under **Controls**, uncheck the boxes next to **Minimize** and **Resize**. Finally, make sure **Visible at launch** is checked. This refers the launch of the *window*, not the *application*.
+
+### Adding the controls
+
+To add content to the window, we need to bring up the **Objects Library** - you can find this under **View** > **Libraries** > **Show Library** from the application menu, hit **Shift+⌘+L**, or click the **Libraries** icon in the toolbar of your Xcode window (it looks like a square inside a circle). Search for the word **label**, and drag a **Label** to the window. Change the **Title** attribute to your application name. Drag a **Multi-line Label** to the window, and position it below the label we just created. Change the **Title** attribute to a short summary (or other information) about your application.
+
+The application icon in this window also serves as a button to open the changelog window. Open the **Objects Library** again, and search for and add an **Image Button**. Change the **Image** attribute of this button to the name of your application icon (in my case, `LunaMac`). Resize and position this button to your liking.
+
+### Activating the window
+
+We're going to go back to our main `AppDelegate.swift` file. In your `buildMenu()` function, add a new menu item above the **Quit application** menu item. This will activate a new `showAbout()` function when clicked.
+
+```swift
+@objc func buildMenu(key: String = "default") {
+ ...
+ statusBarMenu.addItem(
+ withTitle: "About LunaMac...",
+ action: #selector(AppDelegate.showAbout),
+ keyEquivalent: ""
+ )
+ ...
+}
+```
+
+`showAbout()` needs to load this window. To accomplish this, we need to use an instance of [`NSWindowController`](https://developer.apple.com/documentation/appkit/nswindowcontroller) using `InfoBox.xib`.
+
+```swift
+@objc func showAbout() {
+ // create infobox window object
+ let aboutWin = NSWindowController(windowNibName: "InfoBox")
+
+ aboutWin.loadWindow()
+}
+```
+
+To make sure your window shows up on top of any other open windows, add a call to [`NSApp.activate`](https://developer.apple.com/documentation/appkit/nsapplication/1428468-activate).
+
+```swift
+@objc func showAbout() {
+ ...
+ NSApp.activate(ignoringOtherApps: true)
+}
+```
+
+Launch your application, show the "About" window from your icon's menu, and bask in your success. But wait...there's more. Hit that menu item again, and note that you now have a duplicate window. We need to find a way to make sure we're only loading one instance of this window, and resurfacing the same window, rather than duplicating it.
+
+This took awhile to figure out, so maybe I can save you the headache of blindly searching for answers and details.
+
+### Preventing window duplication
+
+Swift follows the MVC model, in which models, views, and controls are separate components of your application. Because of this, we need to use an instance [`NSViewController`](https://developer.apple.com/documentation/appkit/nsviewcontroller), which will give us access to window triggers that fire when the window is opened, closed, changed, etc.
+
+We'll start with adding a [`Bool`](https://developer.apple.com/documentation/swift/bool) scoped to our `AppDelegate` class named `infoOpen`. This is going to keep track of whether or not the "About" window is already open.
+
+```swift
+class AppDelegate: NSObject, NSApplicationDelegate {
+ ...
+ // is the info box open?
+ var infoOpen = false
+ ...
+}
+```
+
+Now we need to add an [`NSViewController`](https://developer.apple.com/documentation/appkit/nsviewcontroller) to `InfoBox.xib`. Open the **Object Library**, and add a **View Controller** to your `xib.`
+
+To make this controller useful, we're going to create a class that inherits from [`NSViewController`](https://developer.apple.com/documentation/appkit/nsviewcontroller).
+
+Add a new Swift file to your project named `ViewController.swift`. Remove the `import Foundation` line at the top, and create your ViewController class. We also need a reference to our `AppDelegate` class, so we can access our `infoOpen` [`Bool`](https://developer.apple.com/documentation/swift/bool).
+
+```swift
+import Cocoa
+class ViewController: NSViewController, NSWindowDelegate {
+ let appDelegate = NSApplication.shared.delegate as! AppDelegate
+}
+```
+
+To handle setting `infoOpen`, we need to override two methods in [`NSViewController`](https://developer.apple.com/documentation/appkit/nsviewcontroller): [`viewDidLoad()`](https://developer.apple.com/documentation/appkit/nsviewcontroller/1434476-viewdidload) and [`viewWillDisappear()`](https://developer.apple.com/documentation/appkit/nsviewcontroller/1434483-viewwilldisappear).
+
+In our [`viewDidLoad()`](https://developer.apple.com/documentation/appkit/nsviewcontroller/1434476-viewdidload) override, we need to call `super.viewDidLoad()`, which ensures the inherited method will still run as expected.
+
+Then, we're going to call a custom function that will load the window, or show it if it's already loaded.
+
+```swift
+override func viewDidLoad() {
+ super.viewDidLoad()
+
+ toggleWindow(boolShow: true)
+}
+```
+
+Our `toggleWindow()` function looks at the title of the window that triggered it, and sets the value of `infoOpen` based on the [`Bool`](https://developer.apple.com/documentation/swift/bool) passed by the original function call. This allows us to use the same function to either show or hide the window.
+
+```swift
+func toggleWindow(boolShow: Bool = false) {
+ // get the window title to set the right bool
+ // window title is in self.view.window.title
+ let winTitle = self.view.window?.title
+
+ if (winTitle?.contains("About") ?? false) {
+ appDelegate.infoOpen = boolShow
+ }
+}
+```
+
+We need something similar when the window closes, which triggers [`viewWillDisappear()`](https://developer.apple.com/documentation/appkit/nsviewcontroller/1434483-viewwilldisappear).
+
+```swift
+// triggers when window is closed
+override func viewWillDisappear() {
+ toggleWindow(boolShow: false)
+}
+```
+
+
+
+Now that we have our custom `ViewController` class, we need to assign it to the **View Controller** we created in `InfoBox.xib`.
+
+In the `xib` file, select the **View Controller**, and open the **Identity Inspector** in the righthand pane of your Xcode window. In the **Custom Class** section, set the **Class** value to **ViewController** (the name of our class).
+
+
+
+This is where things get more than slightly confusing. Xcode relies on a mouse-driven graphical interface for connecting code to windows and controls in windows. To associate the **View Controller** with our window, hold down `Ctrl` while click-and-dragging from **View Controller** in the tree to the **View** in the window - the whole window area excluding the title bar. A little menu will appear; choose **View** under **Outlets**.
+
+
+
+If you look at the source code (XML) view for `InfoBox.xib`, there's now a `` section that references the automatically-generated `id` of the ``. You can manually set these element `id` values, and set up the connection between view and controller directly in the XML.
+
+```xml
+
+ ...
+
+ ...
+
+ ...
+
+
+
+
+
+
+```
+
+Launch your app, and verify that everything works. Now, when you select "About..." from the status bar icon's menu, if the window's already open, it will display, rather than creating a new instance of the window.
+
+### Adding an action to the button
+
+Recall when we created `InfoBox`, we included an **Image Button** using the application's icon. Now we're going to associate a function with this button. First, we'll create a special kind of function using [`@IBAction`](https://developer.apple.com/documentation/uikit/uibutton) in our `AppDelegate` class. *Note: this documentation relates to UIKit, which we aren't using in this application. The `@IBAction` concept is the same.*
+
+When the button is clicked, it calls `clickClick()`, which in turn calls `showLog()`.
+
+```swift
+@IBAction func clickClick(_ sender: NSButtonCell) {
+ // show changelog
+ showLog()
+}
+```
+
+`showLog()` is a simple function that behaves just like `showAbout()`. Add the function to your `AppDelegate` class definition.
+
+```swift
+@objc func showLog() {
+ if (!logOpen) {
+ // create changelog window object
+ // this creates duplicate windows
+ let logWin = NSWindowController(windowNibName: "Changelog")
+
+ logWin.loadWindow()
+ }
+ NSApp.activate(ignoringOtherApps: true)
+}
+```
+
+To connect this action to your button, you can either edit the XML, or use the mouse-driven Interface Builder. The XML is simple:
+
+```xml
+
+ ...
+
+ ...
+
+```
+
+Alternatively, you can `Ctrl`-and-drag from the button's **Button Cell** to the **First Responder** you'll find under **Placeholders**, and select your function `clickClick:` from the list that appears.
+
+Now we need to make a changelog dialog, and the code to load it and its contents.
+
+## The Changelog window
+
+Add a new **Window** document to your project named `Changelog.xib`. Next, add an **Empty** file - this file type can be found in the **Other** section under **MacOS** templates. Name this file `changelog.txt` - we'll load the contents of this file into the changelog window, making it easy to maintain the changelog separate from the application.
+
+Change the **Window** attributes to remove the minimize and maximize buttons, and set the title to `Changelog`. Add a **Scrollable Text View**, and resize it to fill out the window. Navigate through the window tree to the **Text View** that sits under **Scroll View**, and uncheck the box next to **Editable** in the **Attributes Inspector**.
+
+To interact with this window and its contents, we need a **View Controller**. Add one from the **Object Library**. As we did with `InfoBox.xib`, change this **View Controller** to use our custom class named `ViewController`. Connect this **View Controller** to your changelog window's **View**, either through the `Ctrl`-and-drag, or by editing the XML directly in `Changelog.xib`.
+
+Since we're also going to be changing the contents of our **Scrollable Text View**, we need to add an outlet for it, as well.
+
+```xml
+
+ ...
+
+ ...
+
+ ...
+
+
+
+
+
+
+
+```
+
+### Tracking the window status
+
+Displaying the Changelog window also requires a [`Bool`](https://developer.apple.com/documentation/swift/bool) value to track whether it's already open, so add one to your `AppDelegate` class definition in `AppDelegate.swift`.
+
+```swift
+class AppDelegate: NSObject, NSApplicationDelegate {
+ ...
+ // is the info box open?
+ var logOpen = false
+ ...
+}
+```
+
+### Handling the view controller
+
+Then, add the code to `toggleWindow()` in `ViewController.swift` to handle showing the changelog window, similar to how we handled the info window.
+
+```swift
+func toggleWindow(boolShow: Bool = false) {
+ ...
+ if (winTitle?.contains("About") ?? false) {
+ appDelegate.infoOpen = boolShow
+ }
+ else if (winTitle?.contains("Changelog") ?? false) {
+ appDelegate.logOpen = boolShow
+ }
+}
+```
+
+Now you can launch your application and access both the info and changelog windows. We're in the home stretch!
+
+### Loading the changelog file
+
+In our `ViewController` class, we're going to override [`NSViewController.viewDidAppear()`](https://developer.apple.com/documentation/appkit/nsviewcontroller/1434455-viewdidappear) to load and display the contents of `changelog.txt` in our changelog window.
+
+Since `changelog.txt` will be packaged with our application, we can access it as a resource in [`NSBundle.main`](https://developer.apple.com/documentation/foundation/bundle/1410786-main). We'll catch any failures with `?? ""`.
+
+```swift
+override func viewDidAppear() {
+ // use this to load the changelog
+ if (self.view.window?.title.contains("Changelog") ?? false) {
+ // get log file path
+ let logPath = Bundle.main.path(forResource: "changelog.txt", ofType: nil) ?? ""
+ ...
+ }
+}
+```
+
+We'll use Swift's [`String.contentsOfFile()`](https://developer.apple.com/documentation/swift/string/init(contentsoffile:)) method to read the contents of `changelog.txt` into a variable. If the file can't be read for any reason, the window will show a simple error message.
+
+Note the `encoding:` argument ensures the file is read with the right encoding. The full list of supported formats can be found in Apple's documentation for [`String.Encoding`](https://developer.apple.com/documentation/swift/string/encoding).
+
+```swift
+override func viewDidAppear() {
+ // use this to load the changelog
+ if (self.view.window?.title.contains("Changelog") ?? false) {
+ ...
+ // get contents of log file
+ let logText = (try? String(contentsOfFile: logPath, encoding: String.Encoding.utf8)) ?? "Changelog couldn't be read."
+ ...
+ }
+}
+```
+
+To actually change the contents of our scrolling text control, we need to create an [`NSTextStorage`](https://developer.apple.com/documentation/uikit/nstextstorage) object that contains both the string and some formatting. Since the log is formatted as a plain text file, we'll use Apple's standard fixed width font, Monaco.
+
+```swift
+override func viewDidAppear() {
+ // use this to load the changelog
+ if (self.view.window?.title.contains("Changelog") ?? false) {
+ ...
+ // create an object to hold the text and its formatting
+ let textStorage = NSTextStorage(string: logText)
+ textStorage.font = NSFont(name: "Monaco", size: 11)
+ textStorage.foregroundColor = NSColor.textColor
+ ...
+ }
+}
+```
+
+We made it to the finish line! To refer to our text control, we'll use that special syntax again, this time using `@IBOutlet`
+
+```swift
+class ViewController: NSViewController, NSWindowDelegate {
+ @IBOutlet var textView: NSTextView!
+}
+```
+
+We'll assign our `textStorage` object to our `textView`, and we're done!
+
+```swift
+override func viewDidAppear() {
+ ...
+ // replace textView's textStorage contents
+ self.textView?.layoutManager?.replaceTextStorage(textStorage)
+}
+```
+
+Congratulations. You can now make simple Swift applications for MacOS with the concepts illustrated in this project. For the complete project, just clone this repo.
\ No newline at end of file