Swift 4 conversion via Xcode 9.2.

PiperOrigin-RevId: 185923433
diff --git a/src/Tulsi.xcodeproj/project.pbxproj b/src/Tulsi.xcodeproj/project.pbxproj
index b020758..669d5c7 100644
--- a/src/Tulsi.xcodeproj/project.pbxproj
+++ b/src/Tulsi.xcodeproj/project.pbxproj
@@ -787,11 +787,11 @@
 				TargetAttributes = {
 					3D9926621C29F0A20094E098 = {
 						CreatedOnToolsVersion = 7.2;
-						LastSwiftMigration = 0820;
+						LastSwiftMigration = 0920;
 					};
 					3D99266B1C29F0A20094E098 = {
 						CreatedOnToolsVersion = 7.2;
-						LastSwiftMigration = 0820;
+						LastSwiftMigration = 0920;
 					};
 					3DAEE4621C85EB6100BA1C67 = {
 						CreatedOnToolsVersion = 7.2.1;
@@ -799,7 +799,7 @@
 					};
 					8B8F55961BE3ECDC0095AF7F = {
 						CreatedOnToolsVersion = 7.1;
-						LastSwiftMigration = 0820;
+						LastSwiftMigration = 0920;
 					};
 				};
 			};
@@ -1196,6 +1196,8 @@
 				PRODUCT_BUNDLE_IDENTIFIER = "com.google.devinfra.${PRODUCT_NAME}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
+				SWIFT_VERSION = 4.0;
 				VERSIONING_SYSTEM = "";
 			};
 			name = Debug;
@@ -1213,6 +1215,8 @@
 				PRODUCT_BUNDLE_IDENTIFIER = "com.google.devinfra.${PRODUCT_NAME}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
+				SWIFT_VERSION = 4.0;
 				VERSIONING_SYSTEM = "";
 			};
 			name = Release;
@@ -1225,6 +1229,8 @@
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.google.devinfra.${PRODUCT_NAME}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
+				SWIFT_VERSION = 4.0;
 			};
 			name = Debug;
 		};
@@ -1236,6 +1242,8 @@
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.google.devinfra.${PRODUCT_NAME}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
+				SWIFT_VERSION = 4.0;
 			};
 			name = Release;
 		};
@@ -1249,6 +1257,7 @@
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.TulsiGeneratorIntegrationTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
 			};
 			name = Debug;
 		};
@@ -1262,6 +1271,7 @@
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = com.google.Tulsi.TulsiGeneratorIntegrationTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
 			};
 			name = Release;
 		};
@@ -1387,6 +1397,8 @@
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.google.${PRODUCT_NAME}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
+				SWIFT_VERSION = 4.0;
 			};
 			name = Debug;
 		};
@@ -1399,6 +1411,8 @@
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.google.${PRODUCT_NAME}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_SWIFT3_OBJC_INFERENCE = On;
+				SWIFT_VERSION = 4.0;
 			};
 			name = Release;
 		};
diff --git a/src/Tulsi/BazelSelectionPanel.swift b/src/Tulsi/BazelSelectionPanel.swift
index 731a8a9..e188bc4 100644
--- a/src/Tulsi/BazelSelectionPanel.swift
+++ b/src/Tulsi/BazelSelectionPanel.swift
@@ -34,28 +34,30 @@
     panel.prompt = NSLocalizedString("ProjectEditor_SelectBazelPathPrompt",
                                      comment: "Label for the button used to confirm the selected Bazel file in the Bazel selector sheet.")
 
-    var views: NSArray = []
-    Bundle.main.loadNibNamed("BazelOpenSheetAccessoryView",
+    var views: NSArray?
+    Bundle.main.loadNibNamed(NSNib.Name(rawValue: "BazelOpenSheetAccessoryView"),
                              owner: panel,
                              topLevelObjects: &views)
     // Note: topLevelObjects will contain the accessory view and an NSApplication object in a
     // non-deterministic order.
-    views = views.filter() { $0 is NSView } as NSArray
-    if let accessoryView = views.firstObject as? NSView {
-      panel.accessoryView = accessoryView
-      if #available(OSX 10.11, *) {
-        panel.isAccessoryViewDisclosed = true
+    if let views = views {
+      let viewsFound = views.filter() { $0 is NSView } as NSArray
+      if let accessoryView = viewsFound.firstObject as? NSView {
+        panel.accessoryView = accessoryView
+        if #available(OSX 10.11, *) {
+          panel.isAccessoryViewDisclosed = true
+        }
+      } else {
+        assertionFailure("Failed to load accessory view for Bazel open sheet.")
       }
-    } else {
-      assertionFailure("Failed to load accessory view for Bazel open sheet.")
     }
     panel.canChooseDirectories = false
     panel.canChooseFiles = true
     panel.directoryURL = document.bazelURL?.deletingLastPathComponent()
     panel.beginSheetModal(for: window) { value in
-      if value == NSFileHandlingPanelOKButton {
+      if value.rawValue == NSFileHandlingPanelOKButton {
         document.bazelURL = panel.url
-        if panel.bazelSelectorUseAsDefaultCheckbox.state == NSOnState {
+        if panel.bazelSelectorUseAsDefaultCheckbox.state == NSControl.StateValue.on {
           UserDefaults.standard.set(document.bazelURL!, forKey: BazelLocator.DefaultBazelURLKey)
         }
       }
@@ -64,7 +66,7 @@
       // spawns new sheet modals.
       panel.orderOut(panel)
       if let completionHandler = completionHandler {
-        completionHandler(value == NSFileHandlingPanelOKButton ? panel.url : nil)
+        completionHandler(value.rawValue == NSFileHandlingPanelOKButton ? panel.url : nil)
       }
     }
     return panel
diff --git a/src/Tulsi/ConfigEditorBuildTargetSelectorViewController.swift b/src/Tulsi/ConfigEditorBuildTargetSelectorViewController.swift
index d63f196..840e2d7 100644
--- a/src/Tulsi/ConfigEditorBuildTargetSelectorViewController.swift
+++ b/src/Tulsi/ConfigEditorBuildTargetSelectorViewController.swift
@@ -46,7 +46,7 @@
 
   @IBOutlet weak var buildTargetTable: NSTableView!
 
-  dynamic let typeFilter: NSPredicate? = NSPredicate.init(format: "(SELF.type IN %@) OR (SELF.selected == TRUE)",
+  @objc dynamic let typeFilter: NSPredicate? = NSPredicate.init(format: "(SELF.type IN %@) OR (SELF.selected == TRUE)",
                                                           argumentArray: [filteredFileTypes])
 
   var selectedRuleInfoCount: Int = 0 {
@@ -57,9 +57,9 @@
 
   override var representedObject: Any? {
     didSet {
-      unbind("selectedRuleInfoCount")
+      NSObject.unbind(NSBindingName(rawValue: "selectedRuleInfoCount"))
       guard let document = representedObject as? TulsiGeneratorConfigDocument else { return }
-      bind("selectedRuleInfoCount",
+      bind(NSBindingName(rawValue: "selectedRuleInfoCount"),
            to: document,
            withKeyPath: "selectedRuleInfoCount",
            options: nil)
@@ -67,14 +67,14 @@
   }
 
   deinit {
-    unbind("selectedRuleInfoCount")
+    NSObject.unbind(NSBindingName(rawValue: "selectedRuleInfoCount"))
   }
 
   override func loadView() {
     super.loadView()
 
-    let typeColumn = buildTargetTable.tableColumn(withIdentifier: "Type")!
-    let labelColumn = buildTargetTable.tableColumn(withIdentifier: "Label")!
+    let typeColumn = buildTargetTable.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Type"))!
+    let labelColumn = buildTargetTable.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "Label"))!
     buildTargetTable.sortDescriptors = [typeColumn.sortDescriptorPrototype!,
                                         labelColumn.sortDescriptorPrototype!]
   }
@@ -88,6 +88,6 @@
   }
 
   func wizardSubviewDidDeactivate() {
-    unbind("selectedRuleInfoCount")
+    NSObject.unbind(NSBindingName(rawValue: "selectedRuleInfoCount"))
   }
 }
diff --git a/src/Tulsi/ConfigEditorSourceFilterViewController.swift b/src/Tulsi/ConfigEditorSourceFilterViewController.swift
index 03cef03..447e5a3 100644
--- a/src/Tulsi/ConfigEditorSourceFilterViewController.swift
+++ b/src/Tulsi/ConfigEditorSourceFilterViewController.swift
@@ -20,30 +20,30 @@
 
   /// Whether or not this specific node is set as recursive-enabled (rather than some child marking
   /// it as mixed state).
-  dynamic var explicitlyRecursive: Bool {
-    return recursive == NSOnState
+  @objc dynamic var explicitlyRecursive: Bool {
+    return recursive == NSControl.StateValue.on.rawValue
   }
 
   /// This node's recursive UI state (NSOnState/NSOffState/NSMixedState).
-  dynamic var recursive: Int {
+  @objc dynamic var recursive: Int {
     get {
-      guard let entry = entry as? UISourcePath else { return NSOffState }
-      if entry.recursive { return NSOnState }
+      guard let entry = entry as? UISourcePath else { return NSControl.StateValue.off.rawValue }
+      if entry.recursive { return NSControl.StateValue.on.rawValue }
 
       for child in children as! [SourcePathNode] {
-        if child.recursive != NSOffState {
-          return NSMixedState
+        if child.recursive != NSControl.StateValue.off.rawValue {
+          return NSControl.StateValue.mixed.rawValue
         }
       }
-      return NSOffState
+      return NSControl.StateValue.off.rawValue
     }
 
     set {
       // No work needs to be done for mixed state, as it does not affect the underlying values.
-      if newValue == NSMixedState { return }
+      if newValue == NSControl.StateValue.mixed.rawValue { return }
 
       guard let entry = entry as? UISourcePath else { return }
-      let enabled = newValue == NSOnState
+      let enabled = newValue == NSControl.StateValue.on.rawValue
       willChangeValue(forKey: "explicitlyRecursive")
       entry.recursive = enabled
       didChangeValue(forKey: "explicitlyRecursive")
@@ -62,11 +62,11 @@
     }
   }
 
-  dynamic var hasRecursiveEnabledParent: Bool = false {
+  @objc dynamic var hasRecursiveEnabledParent: Bool = false {
     willSet {
       // If this node is recursive its children will still have a recursive parent and there's no
       // need to update them.
-      if recursive == NSOnState || newValue == hasRecursiveEnabledParent { return }
+      if recursive == NSControl.StateValue.on.rawValue || newValue == hasRecursiveEnabledParent { return }
       setChildrenHaveRecursiveParent(newValue)
     }
   }
@@ -74,8 +74,8 @@
   // TODO(abaire): Use a custom control to override nextState: such that it's never set to mixed via user interaction.
   func validateRecursive(_ ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>) throws {
     if let value = ioValue.pointee as? NSNumber {
-      if value.intValue == NSMixedState {
-        ioValue.pointee = NSNumber(value: NSOnState as Int)
+      if value.intValue == NSControl.StateValue.mixed.rawValue {
+        ioValue.pointee = NSNumber(value: NSControl.StateValue.on.rawValue as Int)
       }
     }
   }
@@ -88,7 +88,7 @@
       // Children of a recursive-enabled node may not be recursive themselves (it's redundant and
       // potentially confusing).
       if newValue {
-        child.recursive = NSOffState
+        child.recursive = NSControl.StateValue.off.rawValue
       }
     }
   }
@@ -98,12 +98,12 @@
 // Controller for the view allowing users to select a subset of the source files to include in the
 // generated Xcode project.
 final class ConfigEditorSourceFilterViewController: NSViewController, WizardSubviewProtocol {
-  dynamic var sourceFilterContentArray: [SourcePathNode] = []
+  @objc dynamic var sourceFilterContentArray: [SourcePathNode] = []
   @IBOutlet weak var sourceFilterOutlineView: NSOutlineView!
 
   override func viewDidLoad() {
     super.viewDidLoad()
-    let sourceTargetColumn = sourceFilterOutlineView.tableColumn(withIdentifier: "sourceTargets")!
+    let sourceTargetColumn = sourceFilterOutlineView.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "sourceTargets"))!
     sourceFilterOutlineView.sortDescriptors = [sourceTargetColumn.sortDescriptorPrototype!]
   }
 
@@ -150,7 +150,7 @@
         node = newNode
       }
       node.entry = sourcePaths[i]
-      if node.recursive == NSOnState {
+      if node.recursive == NSControl.StateValue.on.rawValue {
         recursiveNodes.append(node)
       }
     }
diff --git a/src/Tulsi/ConfigEditorWizardViewController.swift b/src/Tulsi/ConfigEditorWizardViewController.swift
index 45cc2be..c970059 100644
--- a/src/Tulsi/ConfigEditorWizardViewController.swift
+++ b/src/Tulsi/ConfigEditorWizardViewController.swift
@@ -37,7 +37,7 @@
   }
 
   override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
-    if segue.identifier == "Embed Wizard PageController" {
+    if segue.identifier!.rawValue == "Embed Wizard PageController" {
       pageViewController = (segue.destinationController as! NSPageController)
       pageViewController.arrangedObjects = ConfigEditorWizardViewController.wizardPageIdentifiers
       pageViewController.delegate = self
@@ -113,16 +113,16 @@
 
   // MARK: - NSPageControllerDelegate
 
-  func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
-    return object as! String
+  func pageController(_ pageController: NSPageController, identifierFor object: Any) -> NSPageController.ObjectIdentifier {
+    return NSPageController.ObjectIdentifier(rawValue: object as! String)
   }
 
-  func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
-    let vc = storyboard!.instantiateController(withIdentifier: identifier) as! NSViewController
+  func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: NSPageController.ObjectIdentifier) -> NSViewController {
+    let vc = storyboard!.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: identifier.rawValue)) as! NSViewController
 
     // NSPageController doesn't appear to support Autolayout properly, so fall back to
     // autoresizingMask.
-    vc.view.autoresizingMask = [.viewWidthSizable, .viewHeightSizable]
+    vc.view.autoresizingMask = [NSView.AutoresizingMask.width, NSView.AutoresizingMask.height]
     return vc
   }
 
diff --git a/src/Tulsi/HeadlessXcodeProjectGenerator.swift b/src/Tulsi/HeadlessXcodeProjectGenerator.swift
index 99d5be6..a912099 100644
--- a/src/Tulsi/HeadlessXcodeProjectGenerator.swift
+++ b/src/Tulsi/HeadlessXcodeProjectGenerator.swift
@@ -46,7 +46,7 @@
 
     let (projectURL, configURL, defaultOutputFolderURL) = try resolveConfigPath(configPath)
 
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
     let doc: NSDocument
     do {
       doc = try documentController.makeDocument(withContentsOf: projectURL,
@@ -119,7 +119,7 @@
         print("Generated project at \(url.path)")
         if arguments.openXcodeOnSuccess {
           print("Opening generated project in Xcode")
-          NSWorkspace.shared().open(url)
+          NSWorkspace.shared.open(url)
         }
       case .failure:
         throw HeadlessModeError.generationFailed
diff --git a/src/Tulsi/MessageViewController.swift b/src/Tulsi/MessageViewController.swift
index e411fd9..f4a3bbb 100644
--- a/src/Tulsi/MessageViewController.swift
+++ b/src/Tulsi/MessageViewController.swift
@@ -22,7 +22,7 @@
     super.viewDidEndLiveResize()
 
     // Give the delegate a chance to handle the resize now that the live operation is completed.
-    NotificationCenter.default.post(name: NSNotification.Name.NSTableViewColumnDidResize,
+    NotificationCenter.default.post(name: NSTableView.columnDidResizeNotification,
                                                               object: self)
   }
 }
@@ -38,7 +38,7 @@
   // Display heights of each row in the message table.
   var rowHeights = [Int: CGFloat]()
 
-  dynamic var messageCount: Int = 0 {
+  @objc dynamic var messageCount: Int = 0 {
     didSet {
       // Assume that a reduction in the message count means all cached heights are invalid.
       if messageCount < oldValue {
@@ -52,7 +52,7 @@
     ValueTransformer.setValueTransformer(MessageTypeToImageValueTransformer(),
                                            forName: NSValueTransformerName(rawValue: "MessageTypeToImageValueTransformer"))
     super.loadView()
-    bind("messageCount", to: messageArrayController, withKeyPath: "arrangedObjects.@count", options: nil)
+    bind(NSBindingName(rawValue: "messageCount"), to: messageArrayController, withKeyPath: "arrangedObjects.@count", options: nil)
   }
 
   @IBAction func copy(_ sender: AnyObject?) {
@@ -60,7 +60,7 @@
       return
     }
 
-    let pasteboard = NSPasteboard.general()
+    let pasteboard = NSPasteboard.general
     pasteboard.clearContents()
     pasteboard.writeObjects(selectedItems)
   }
@@ -103,7 +103,7 @@
     }
     // Disable animation.
     NSAnimationContext.beginGrouping()
-    NSAnimationContext.current().duration = 0
+    NSAnimationContext.current.duration = 0
     rowHeights.removeAll(keepingCapacity: true)
     let numRows = (messageArrayController.arrangedObjects as AnyObject).count!
     let allRowsIndex = IndexSet(integersIn: 0..<numRows)
@@ -153,11 +153,11 @@
 
     switch messageType {
       case .info, .debug, .syslog:
-        return NSImage(named: "message_info")
+        return NSImage(named: NSImage.Name(rawValue: "message_info"))
       case .warning:
-        return NSImage(named: "message_warning")
+        return NSImage(named: NSImage.Name(rawValue: "message_warning"))
       case .error:
-        return NSImage(named: "message_error")
+        return NSImage(named: NSImage.Name(rawValue: "message_error"))
     }
   }
 }
diff --git a/src/Tulsi/NewGeneratorConfigViewController.swift b/src/Tulsi/NewGeneratorConfigViewController.swift
index 5423d3e..ca0ec9d 100644
--- a/src/Tulsi/NewGeneratorConfigViewController.swift
+++ b/src/Tulsi/NewGeneratorConfigViewController.swift
@@ -32,7 +32,7 @@
 
   weak var delegate: NewGeneratorConfigViewControllerDelegate?
 
-  dynamic var configName: String? = nil
+  @objc dynamic var configName: String? = nil
 
   @IBAction func didClickCancelButton(_ sender: NSButton) {
     delegate?.viewController(self, didCompleteWithReason: .cancel)
diff --git a/src/Tulsi/NewProjectViewController.swift b/src/Tulsi/NewProjectViewController.swift
index e173637..b0a1cf1 100644
--- a/src/Tulsi/NewProjectViewController.swift
+++ b/src/Tulsi/NewProjectViewController.swift
@@ -29,8 +29,8 @@
     case cancel, create
   }
 
-  dynamic var projectName: String? = nil
-  dynamic var workspacePath: URL? = nil
+  @objc dynamic var projectName: String? = nil
+  @objc dynamic var workspacePath: URL? = nil
 
   weak var delegate: NewProjectViewControllerDelegate?
 
@@ -66,7 +66,7 @@
     panel.canChooseDirectories = false
     panel.canChooseFiles = true
     panel.beginSheetModal(for: self.view.window!) { value in
-      if value == NSFileHandlingPanelOKButton {
+      if value.rawValue == NSFileHandlingPanelOKButton {
         self.workspacePath = panel.url
       }
     }
diff --git a/src/Tulsi/OptionsEditorController.swift b/src/Tulsi/OptionsEditorController.swift
index ba9ae83..9c477aa 100644
--- a/src/Tulsi/OptionsEditorController.swift
+++ b/src/Tulsi/OptionsEditorController.swift
@@ -90,7 +90,7 @@
         backgroundColor.setFill()
       }
 
-      NSRectFill(dirtyRect)
+      dirtyRect.fill()
     }
     super.draw(dirtyRect)
   }
@@ -121,7 +121,7 @@
 
 /// View controller for the multiline popup editor displayed when a user double clicks an option.
 final class OptionsEditorPopoverViewController: NSViewController, NSTextFieldDelegate {
-  dynamic var value: String? = nil
+  @objc dynamic var value: String? = nil
 
   enum CloseReason {
     case cancel, accept
@@ -205,7 +205,7 @@
   // The table column used to display build target-specific build options.
   let targetValueColumn: NSTableColumn
 
-  dynamic var nodes = [OptionsEditorNode]()
+  @objc dynamic var nodes = [OptionsEditorNode]()
   weak var model: OptionsEditorModelProtocol? = nil {
     didSet {
       guard let model = model else { return }
@@ -221,9 +221,9 @@
   init(view: NSOutlineView, storyboard: NSStoryboard) {
     self.view = view
     self.storyboard = storyboard
-    defaultValueColumn = view.tableColumn(withIdentifier: OptionsEditorController.defaultColumnIdentifier)!
-    projectValueColumn = view.tableColumn(withIdentifier: OptionsEditorController.projectColumnIdentifier)!
-    targetValueColumn = view.tableColumn(withIdentifier: OptionsEditorController.targetColumnIdentifier)!
+    defaultValueColumn = view.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: OptionsEditorController.defaultColumnIdentifier))!
+    projectValueColumn = view.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: OptionsEditorController.projectColumnIdentifier))!
+    targetValueColumn = view.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: OptionsEditorController.targetColumnIdentifier))!
     super.init()
     self.view.delegate = self
   }
@@ -288,8 +288,8 @@
 
     let clickedColumn = editor.tableColumns[editor.clickedColumn]
     let columnIdentifier = clickedColumn.identifier
-    guard let optionLevel = OptionsEditorNode.OptionLevel(rawValue: columnIdentifier) else {
-      assert(columnIdentifier == OptionsEditorController.settingColumnIdentifier,
+    guard let optionLevel = OptionsEditorNode.OptionLevel(rawValue: columnIdentifier.rawValue) else {
+      assert(columnIdentifier.rawValue == OptionsEditorController.settingColumnIdentifier,
              "Mismatch in storyboard column identifier and OptionLevel enum")
       return
     }
@@ -297,7 +297,7 @@
     let optionNode = optionNodeForItem(optionItem as AnyObject, outlineView: editor)
 
     // Verify that the column is editable.
-    if OptionsEditorController.bindingsControlledColumns.contains(columnIdentifier) ||
+    if OptionsEditorController.bindingsControlledColumns.contains(columnIdentifier.rawValue) ||
         !optionNode.editableForOptionLevel(optionLevel) {
       return
     }
@@ -309,7 +309,7 @@
 
       popoverEditor = NSPopover()
       if popoverViewController == nil {
-        popoverViewController = storyboard.instantiateController(withIdentifier: "OptionsEditorPopover") as? OptionsEditorPopoverViewController
+        popoverViewController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "OptionsEditorPopover")) as? OptionsEditorPopoverViewController
       }
       popoverEditor.contentViewController = popoverViewController
       popoverViewController.optionItem = optionItem as AnyObject?
@@ -339,12 +339,12 @@
     if tableColumn == nil { return nil }
 
     let identifier = tableColumn!.identifier
-    if OptionsEditorController.bindingsControlledColumns.contains(identifier) {
-      return outlineView.make(withIdentifier: identifier, owner: self)
+    if OptionsEditorController.bindingsControlledColumns.contains(identifier.rawValue) {
+      return outlineView.makeView(withIdentifier: identifier, owner: self)
     }
 
     let optionNode = optionNodeForItem(item as AnyObject, outlineView: outlineView)
-    let optionLevel = OptionsEditorNode.OptionLevel(rawValue: identifier)!
+    let optionLevel = OptionsEditorNode.OptionLevel(rawValue: identifier.rawValue)!
     let (displayItem, inherited) = optionNode.displayItemForOptionLevel(optionLevel)
     let explicit = !inherited
     let highlighted = explicit && optionLevel == optionNode.mostSpecializedOptionLevel
@@ -353,7 +353,7 @@
     let view: NSView?
     switch optionNode.valueType {
       case .string:
-        view = outlineView.make(withIdentifier: OptionsEditorController.tableCellViewIdentifier,
+        view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: OptionsEditorController.tableCellViewIdentifier),
                                                   owner: self)
         if let tableCellView = view as? TextTableCellView {
           prepareTableCellView(tableCellView,
@@ -373,7 +373,7 @@
         else {
           identifier = OptionsEditorController.popUpButtonCellViewIdentifier
         }
-        view = outlineView.make(withIdentifier: identifier, owner: self)
+        view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: identifier), owner: self)
         if let tableCellView = view as? PopUpButtonTableCellView {
           preparePopUpButtonTableCellView(tableCellView,
                                           withMenuItems: optionNode.multiSelectItems,
@@ -406,7 +406,7 @@
   // MARK: - NSPopoverDelegate
 
   func popoverDidClose(_ notification: Notification) {
-    if notification.userInfo?[NSPopoverCloseReasonKey] as? String != NSPopoverCloseReasonStandard {
+    if notification.userInfo?[NSPopover.closeReasonUserInfoKey] as? String != NSPopover.CloseReason.standard.rawValue {
       return
     }
 
@@ -431,7 +431,7 @@
     let node = optionNodeForItem(item! as AnyObject, outlineView: view)
     let columnIndex = view.column(for: control)
     let columnIdentifier = view.tableColumns[columnIndex].identifier
-    let level = OptionsEditorNode.OptionLevel(rawValue: columnIdentifier)!
+    let level = OptionsEditorNode.OptionLevel(rawValue: columnIdentifier.rawValue)!
     return (node, level)
   }
 
@@ -452,7 +452,7 @@
     }
 
     let attributedValue = NSMutableAttributedString(string: value)
-    attributedValue.setAttributes([NSFontAttributeName: fontForOption(explicit)],
+    attributedValue.setAttributes([NSAttributedStringKey.font: fontForOption(explicit)],
                                   range: NSRange(location: 0, length: attributedValue.length))
     textField.attributedStringValue = attributedValue
   }
diff --git a/src/Tulsi/OptionsEditorModelProtocol.swift b/src/Tulsi/OptionsEditorModelProtocol.swift
index 36773f2..6ef02b3 100644
--- a/src/Tulsi/OptionsEditorModelProtocol.swift
+++ b/src/Tulsi/OptionsEditorModelProtocol.swift
@@ -39,7 +39,7 @@
   func parentOptionForOptionKey(_ key: TulsiOptionKey) -> TulsiOption?
 
   /// Notifies the receiver that a change has been made to an option.
-  func updateChangeCount(_ change: NSDocumentChangeType)
+  func updateChangeCount(_ change: NSDocument.ChangeType)
 }
 
 extension OptionsEditorModelProtocol {
diff --git a/src/Tulsi/OptionsEditorNode.swift b/src/Tulsi/OptionsEditorNode.swift
index 540633b..4b16d49 100644
--- a/src/Tulsi/OptionsEditorNode.swift
+++ b/src/Tulsi/OptionsEditorNode.swift
@@ -62,7 +62,7 @@
   }
 
   /// This node's children.
-  var children = [OptionsEditorNode]()
+  @objc var children = [OptionsEditorNode]()
 
   func editableForOptionLevel(_ level: OptionLevel) -> Bool {
     assertionFailure("Must be overridden by subclasses")
diff --git a/src/Tulsi/OptionsEditorViewController.swift b/src/Tulsi/OptionsEditorViewController.swift
index 155d58f..9e863fd 100644
--- a/src/Tulsi/OptionsEditorViewController.swift
+++ b/src/Tulsi/OptionsEditorViewController.swift
@@ -22,8 +22,8 @@
   @IBOutlet weak var targetSelectorView: NSOutlineView!
   @IBOutlet weak var optionEditorView: NSOutlineView!
 
-  dynamic var targetSelectorController: OptionsTargetSelectorController? = nil
-  dynamic var editorController: OptionsEditorController? = nil
+  @objc dynamic var targetSelectorController: OptionsTargetSelectorController? = nil
+  @objc dynamic var editorController: OptionsEditorController? = nil
 
   override var representedObject: Any? {
     didSet {
diff --git a/src/Tulsi/OptionsTargetSelectorController.swift b/src/Tulsi/OptionsTargetSelectorController.swift
index 13d3e26..4685d40 100644
--- a/src/Tulsi/OptionsTargetSelectorController.swift
+++ b/src/Tulsi/OptionsTargetSelectorController.swift
@@ -20,9 +20,9 @@
 class OptionsTargetNode: UISelectableOutlineViewNode {
 
   /// Tooltip to be displayed for this node.
-  var toolTip: String? = nil
+  @objc var toolTip: String? = nil
 
-  var boldFont: Bool {
+  @objc var boldFont: Bool {
     return !children.isEmpty
   }
 }
@@ -44,7 +44,7 @@
                         comment: "Short header shown before the build targets in the options editor's target selector.")
 
   weak var view: NSOutlineView!
-  dynamic var nodes = [OptionsTargetNode]()
+  @objc dynamic var nodes = [OptionsTargetNode]()
 
   weak var delegate: OptionsTargetSelectorControllerDelegate?
   weak var model: OptionsEditorModelProtocol! = nil {
diff --git a/src/Tulsi/ProjectEditorConfigManagerViewController.swift b/src/Tulsi/ProjectEditorConfigManagerViewController.swift
index 243fb9a..b6b8704 100644
--- a/src/Tulsi/ProjectEditorConfigManagerViewController.swift
+++ b/src/Tulsi/ProjectEditorConfigManagerViewController.swift
@@ -33,7 +33,7 @@
   @IBOutlet var configArrayController: NSArrayController!
   @IBOutlet weak var addRemoveSegmentedControl: NSSegmentedControl!
 
-  dynamic var numBazelPackages: Int = 0 {
+  @objc dynamic var numBazelPackages: Int = 0 {
     didSet {
       let enableAddButton = numBazelPackages > 0
       addRemoveSegmentedControl.setEnabled(enableAddButton,
@@ -41,7 +41,7 @@
     }
   }
 
-  dynamic var numSelectedConfigs: Int = 0 {
+  @objc dynamic var numSelectedConfigs: Int = 0 {
     didSet {
       addRemoveSegmentedControl.setEnabled(numSelectedConfigs > 0,
                                            forSegment: SegmentedControlButtonIndex.remove.rawValue)
@@ -53,7 +53,7 @@
   override var representedObject: Any? {
     didSet {
       if let concreteRepresentedObject = representedObject {
-        bind("numBazelPackages",
+        bind(NSBindingName(rawValue: "numBazelPackages"),
              to: concreteRepresentedObject,
              withKeyPath: "bazelPackages.@count",
              options: nil)
@@ -62,15 +62,15 @@
   }
 
   deinit {
-    unbind("numBazelPackages")
-    unbind("numSelectedConfigs")
+    NSObject.unbind(NSBindingName(rawValue: "numBazelPackages"))
+    NSObject.unbind(NSBindingName(rawValue: "numSelectedConfigs"))
   }
 
   override func loadView() {
     ValueTransformer.setValueTransformer(IsOneValueTransformer(),
                                            forName: NSValueTransformerName(rawValue: "IsOneValueTransformer"))
     super.loadView()
-    bind("numSelectedConfigs",
+    bind(NSBindingName(rawValue: "numSelectedConfigs"),
          to: configArrayController,
          withKeyPath: "selectedObjects.@count",
          options: nil)
@@ -110,7 +110,7 @@
       if let projectURL = projectURL {
         LogMessage.postInfo("Opening generated project in Xcode",
                             context: projectDocument.projectName)
-        NSWorkspace.shared().open(projectURL)
+        NSWorkspace.shared.open(projectURL)
       }
     }
   }
@@ -123,7 +123,7 @@
     editConfigNamed(configName)
   }
 
-  func document(_ doc:NSDocument, didSave:Bool, contextInfo: UnsafeMutableRawPointer) {
+  @objc func document(_ doc:NSDocument, didSave:Bool, contextInfo: UnsafeMutableRawPointer) {
     if contextInfo == &ProjectEditorConfigManagerViewController.PostSaveContextAddConfig {
       if didSave {
         didClickAddConfig(nil)
@@ -142,7 +142,7 @@
     guard let bazelPackages = projectDocument.bazelPackages, !bazelPackages.isEmpty else {
       // This should be prevented by the UI, so spawn a bug message and beep.
       LogMessage.postInfo("Bug: Add config invoked on a project with no packages.")
-      NSBeep()
+      NSSound.beep()
       return
     }
 
diff --git a/src/Tulsi/ProjectEditorPackageManagerViewController.swift b/src/Tulsi/ProjectEditorPackageManagerViewController.swift
index e6f328c..7f4dd2a 100644
--- a/src/Tulsi/ProjectEditorPackageManagerViewController.swift
+++ b/src/Tulsi/ProjectEditorPackageManagerViewController.swift
@@ -31,7 +31,7 @@
   var newProjectSheet: NewProjectViewController! = nil
   private var newProjectNeedsSaveAs = false
 
-  dynamic var numSelectedPackagePaths: Int = 0 {
+  @objc dynamic var numSelectedPackagePaths: Int = 0 {
     didSet {
       let enableRemoveButton = numSelectedPackagePaths > 0
       addRemoveSegmentedControl.setEnabled(enableRemoveButton,
@@ -40,14 +40,14 @@
   }
 
   deinit {
-    unbind("numSelectedPackagePaths")
+    NSObject.unbind(NSBindingName(rawValue: "numSelectedPackagePaths"))
   }
 
   override func loadView() {
     ValueTransformer.setValueTransformer(PackagePathValueTransformer(),
                                            forName: NSValueTransformerName(rawValue: "PackagePathValueTransformer"))
     super.loadView()
-    bind("numSelectedPackagePaths",
+    bind(NSBindingName(rawValue: "numSelectedPackagePaths"),
          to: packageArrayController,
          withKeyPath: "selectedObjects.@count",
          options: nil)
@@ -118,12 +118,12 @@
                                      comment: "Label for the button used to confirm adding the selected BUILD file to the Tulsi project.")
     panel.canChooseDirectories = false
     panel.beginSheetModal(for: self.view.window!) { value in
-      if value == NSFileHandlingPanelOKButton {
+      if value.rawValue == NSFileHandlingPanelOKButton {
         guard let URL = panel.url else {
           return
         }
         if !document.addBUILDFileURL(URL) {
-          NSBeep()
+          NSSound.beep()
         }
       }
     }
@@ -140,7 +140,7 @@
       alert.addButton(withTitle: NSLocalizedString("ProjectEditor_CloseOpenedConfigDocumentsButtonCancel",
                                                  comment: "Title for a button that will cancel an operation that requires that all opened TulsiGeneratorConfig documents be closed."))
       alert.beginSheetModal(for: self.view.window!) { value in
-        if value == NSAlertFirstButtonReturn {
+        if value == NSApplication.ModalResponse.alertFirstButtonReturn {
           document.closeChildConfigDocuments()
           self.didClickRemoveSelectedBUILDFiles(sender)
         }
@@ -166,7 +166,7 @@
     let document = representedObject as! TulsiProjectDocument
     let buildFile = package + "/BUILD"
     if let url = document.workspaceRootURL?.appendingPathComponent(buildFile) {
-      NSWorkspace.shared().open(url)
+      NSWorkspace.shared.open(url)
     }
   }
 
diff --git a/src/Tulsi/SplashScreenWindowController.swift b/src/Tulsi/SplashScreenWindowController.swift
index 7e4a3cf..ab7d2d5 100644
--- a/src/Tulsi/SplashScreenWindowController.swift
+++ b/src/Tulsi/SplashScreenWindowController.swift
@@ -20,13 +20,13 @@
   @IBOutlet weak var path: NSTextField!
   var url: URL?
 
-  override var nibName: String? {
-    return "SplashScreenRecentDocumentView"
+  override var nibName: NSNib.Name? {
+    return NSNib.Name(rawValue: "SplashScreenRecentDocumentView")
   }
 
   override func viewDidLoad() {
     guard let url = url else { return }
-    icon.image =  NSWorkspace.shared().icon(forFile: url.path)
+    icon.image =  NSWorkspace.shared.icon(forFile: url.path)
     filename.stringValue = (url.lastPathComponent as NSString).deletingPathExtension
     path.stringValue = ((url.path as NSString).deletingLastPathComponent as NSString).abbreviatingWithTildeInPath
   }
@@ -37,17 +37,17 @@
 
   @IBOutlet var recentDocumentsArrayController: NSArrayController!
   @IBOutlet weak var splashScreenImageView: NSImageView!
-  dynamic var applicationVersion: String = ""
-  dynamic var recentDocumentViewControllers = [SplashScreenRecentDocumentViewController]()
+  @objc dynamic var applicationVersion: String = ""
+  @objc dynamic var recentDocumentViewControllers = [SplashScreenRecentDocumentViewController]()
 
-  override var windowNibName: String? {
-    return "SplashScreenWindowController"
+  override var windowNibName: NSNib.Name? {
+    return NSNib.Name(rawValue: "SplashScreenWindowController")
   }
 
   override func windowDidLoad() {
     super.windowDidLoad()
 
-    splashScreenImageView.image = NSApplication.shared().applicationIconImage
+    splashScreenImageView.image = NSApplication.shared.applicationIconImage
 
     if let cfBundleVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
       applicationVersion = cfBundleVersion
@@ -57,7 +57,7 @@
   }
 
   @IBAction func createNewDocument(_ sender: NSButton) {
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
     do {
       try documentController.openUntitledDocumentAndDisplay(true)
     } catch let e as NSError {
@@ -71,7 +71,7 @@
   @IBAction func didDoubleClickRecentDocument(_ sender: NSTableView) {
     let clickedRow = sender.clickedRow
     guard clickedRow >= 0 else { return }
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
     let viewController = recentDocumentViewControllers[clickedRow]
 
     guard let url = viewController.url  else { return }
@@ -92,7 +92,7 @@
 
   private func getRecentDocumentViewControllers() -> [SplashScreenRecentDocumentViewController] {
     let projectExtension = TulsiProjectDocument.getTulsiBundleExtension()
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
 
     var recentDocumentViewControllers = [SplashScreenRecentDocumentViewController]()
     var recentDocumentURLs = Set<URL>()
diff --git a/src/Tulsi/TulsiGeneratorConfigDocument.swift b/src/Tulsi/TulsiGeneratorConfigDocument.swift
index 1c74293..2de2900 100644
--- a/src/Tulsi/TulsiGeneratorConfigDocument.swift
+++ b/src/Tulsi/TulsiGeneratorConfigDocument.swift
@@ -50,7 +50,7 @@
   weak var delegate: TulsiGeneratorConfigDocumentDelegate? = nil
 
   /// Whether or not the document is currently performing a long running operation.
-  dynamic var processing: Bool = false
+  @objc dynamic var processing: Bool = false
 
   // The number of tasks that need to complete before processing is finished. May only be mutated on
   // the main queue.
@@ -62,7 +62,7 @@
   }
 
   // The folder into which the generated Xcode project will be written.
-  dynamic var outputFolderURL: URL? = nil
+  @objc dynamic var outputFolderURL: URL? = nil
 
   /// The set of all RuleInfo instances from which the user can select build targets.
   // Maps the given RuleInfo instances to UIRuleInfo's, preserving this config's selections if
@@ -89,7 +89,7 @@
   }
 
   /// The UIRuleEntry instances that are acted on by the associated UI.
-  dynamic var uiRuleInfos = [UIRuleInfo]() {
+  @objc dynamic var uiRuleInfos = [UIRuleInfo]() {
     willSet {
       stopObservingRuleEntries()
 
@@ -112,7 +112,7 @@
   }
 
   /// The number of selected items in ruleEntries.
-  dynamic var selectedRuleInfoCount: Int = 0 {
+  @objc dynamic var selectedRuleInfoCount: Int = 0 {
     didSet {
       updateChangeCount(.changeDone)  // TODO(abaire): Implement undo functionality.
     }
@@ -176,7 +176,7 @@
                                                  additionalFilePaths: [String]? = nil,
                                                  bazelURL: URL? = nil,
                                                  name: String? = nil) throws -> TulsiGeneratorConfigDocument {
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
     guard let doc = try documentController.makeUntitledDocument(ofType: TulsiGeneratorConfigDocument.FileType) as? TulsiGeneratorConfigDocument else {
       throw TulsiError(errorMessage: "Document for type \(TulsiGeneratorConfigDocument.FileType) was not the expected type.")
     }
@@ -219,7 +219,7 @@
                                                   infoExtractor: TulsiProjectInfoExtractor,
                                                   messageLog: MessageLogProtocol?,
                                                   bazelURL: URL? = nil) throws -> TulsiGeneratorConfigDocument {
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
     guard let doc = try documentController.makeDocument(withContentsOf: url,
                                                                          ofType: TulsiGeneratorConfigDocument.FileType) as? TulsiGeneratorConfigDocument else {
       throw TulsiError(errorMessage: "Document for type \(TulsiGeneratorConfigDocument.FileType) was not the expected type.")
@@ -278,7 +278,7 @@
   }
 
   deinit {
-    unbind("projectRuleEntries")
+    NSObject.unbind(NSBindingName(rawValue: "projectRuleEntries"))
     stopObservingRuleEntries()
     assert(saveCompletionHandler == nil)
   }
@@ -296,8 +296,8 @@
   }
 
   override func makeWindowControllers() {
-    let storyboard = NSStoryboard(name: "Main", bundle: nil)
-    let windowController = storyboard.instantiateController(withIdentifier: "TulsiGeneratorConfigDocumentWindow") as! NSWindowController
+    let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
+    let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "TulsiGeneratorConfigDocumentWindow")) as! NSWindowController
     windowController.contentViewController?.representedObject = self
     // TODO(abaire): Consider supporting restoration of config subwindows.
     windowController.window?.isRestorable = false
@@ -337,7 +337,7 @@
 
   override func save(to url: URL,
                      ofType typeName: String,
-                     for saveOperation: NSSaveOperationType,
+                     for saveOperation: NSDocument.SaveOperationType,
                      completionHandler: @escaping (Error?) -> Void) {
     var writeError: NSError? = nil
     do {
@@ -408,7 +408,7 @@
     }
   }
 
-  override class func autosavesInPlace() -> Bool {
+  override class var autosavesInPlace: Bool {
     // TODO(abaire): Enable autosave when undo behavior is implemented.
     return false
   }
diff --git a/src/Tulsi/TulsiProjectDocument.swift b/src/Tulsi/TulsiProjectDocument.swift
index b6f7adb..9c23c39 100644
--- a/src/Tulsi/TulsiProjectDocument.swift
+++ b/src/Tulsi/TulsiProjectDocument.swift
@@ -53,7 +53,7 @@
   var project: TulsiProject! = nil
 
   /// Whether or not the document is currently performing a long running operation.
-  dynamic var processing: Bool = false
+  @objc dynamic var processing: Bool = false
 
   // The number of tasks that need to complete before processing is finished. May only be mutated on
   // the main queue.
@@ -65,7 +65,7 @@
   }
 
   /// The display names of generator configs associated with this project.
-  dynamic var generatorConfigNames = [String]()
+  @objc dynamic var generatorConfigNames = [String]()
 
   /// Whether or not there are any opened generator config documents associated with this project.
   var hasChildConfigDocuments: Bool {
@@ -91,7 +91,7 @@
   }
 
   /// The set of Bazel packages associated with this project.
-  dynamic var bazelPackages: [String]? {
+  @objc dynamic var bazelPackages: [String]? {
     set {
       project!.bazelPackages = newValue ?? [String]()
       updateChangeCount(.changeDone)  // TODO(abaire): Implement undo functionality.
@@ -103,7 +103,7 @@
   }
 
   /// Location of the bazel binary.
-  dynamic var bazelURL: URL? {
+  @objc dynamic var bazelURL: URL? {
     set {
       project.bazelURL = newValue
       if newValue != nil && infoExtractor != nil {
@@ -118,7 +118,7 @@
   }
 
   /// Binding point for the directory containing the project's WORKSPACE file.
-  dynamic var workspaceRootURL: URL? {
+  @objc dynamic var workspaceRootURL: URL? {
     return project?.workspaceRootURL
   }
 
@@ -131,7 +131,7 @@
   private var logEventObserver: NSObjectProtocol! = nil
 
   /// Array of user-facing messages, generally output by the Tulsi generator.
-  dynamic var messages = [UIMessage]()
+  @objc dynamic var messages = [UIMessage]()
 
   lazy var bundleExtension: String = {
     TulsiProjectDocument.getTulsiBundleExtension()
@@ -205,14 +205,14 @@
 
   override func writeSafely(to url: URL,
                             ofType typeName: String,
-                            for saveOperation: NSSaveOperationType) throws {
+                            for saveOperation: NSDocument.SaveOperationType) throws {
     // Ensure that the project's URL is set to the location in which this document is being saved so
     // that relative paths can be set properly.
     project.projectBundleURL = url
     try super.writeSafely(to: url, ofType: typeName, for: saveOperation)
   }
 
-  override class func autosavesInPlace() -> Bool {
+  override class var autosavesInPlace: Bool {
     return true
   }
 
@@ -300,8 +300,8 @@
   }
 
   override func makeWindowControllers() {
-    let storyboard = NSStoryboard(name: "Main", bundle: nil)
-    let windowController = storyboard.instantiateController(withIdentifier: "TulsiProjectDocumentWindow") as! NSWindowController
+    let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
+    let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "TulsiProjectDocumentWindow")) as! NSWindowController
     windowController.contentViewController?.representedObject = self
     addWindowController(windowController)
   }
@@ -386,7 +386,7 @@
       throw DocumentError.noSuchConfig
     }
 
-    let documentController = NSDocumentController.shared()
+    let documentController = NSDocumentController.shared
     if let configDocument = documentController.document(for: configURL) as? TulsiGeneratorConfigDocument {
       return configDocument
     }
@@ -564,7 +564,7 @@
 
 /// Convenience class for displaying an error message with an optional detail accessory view.
 class ErrorAlertView: NSAlert {
-  dynamic var text = ""
+  @objc dynamic var text = ""
 
   static func displayModalError(_ message: String, details: String? = nil) {
     let alert = ErrorAlertView()
@@ -575,17 +575,19 @@
     if let details = details {
       alert.text = details
 
-      var views: NSArray = []
-      Bundle.main.loadNibNamed("ErrorAlertDetailView",
+      var views: NSArray?
+      Bundle.main.loadNibNamed(NSNib.Name(rawValue: "ErrorAlertDetailView"),
                                          owner: alert,
                                          topLevelObjects: &views)
       // Note: topLevelObjects will contain the accessory view and an NSApplication object in a
       // non-deterministic order.
-      views = views.filter() { $0 is NSView } as NSArray
-      if let accessoryView = views.firstObject as? NSScrollView {
-        alert.accessoryView = accessoryView
-      } else {
-        assertionFailure("Failed to load accessory view for error alert.")
+      if let views = views {
+        let viewsFound = views.filter() { $0 is NSView } as NSArray
+        if let accessoryView = viewsFound.firstObject as? NSScrollView {
+          alert.accessoryView = accessoryView
+        } else {
+          assertionFailure("Failed to load accessory view for error alert.")
+        }
       }
     }
     alert.runModal()
diff --git a/src/Tulsi/UIMessage.swift b/src/Tulsi/UIMessage.swift
index 246f503..7e86679 100644
--- a/src/Tulsi/UIMessage.swift
+++ b/src/Tulsi/UIMessage.swift
@@ -23,8 +23,8 @@
 
 /// Models a single user-facing message.
 final class UIMessage: NSObject, NSPasteboardWriting {
-  dynamic let text: String
-  dynamic let messagePriority: TulsiGenerator.LogMessagePriority
+  @objc dynamic let text: String
+  @objc dynamic let messagePriority: TulsiGenerator.LogMessagePriority
   let timestamp = Date()
 
   init(text: String, type: TulsiGenerator.LogMessagePriority) {
@@ -34,12 +34,12 @@
 
   // MARK: - NSPasteboardWriting
 
-  func writableTypes(for pasteboard: NSPasteboard) -> [String] {
-    return [NSPasteboardTypeString]
+  func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] {
+    return [NSPasteboard.PasteboardType.string]
   }
 
-  func pasteboardPropertyList(forType type: String) -> Any? {
-    if type == NSPasteboardTypeString {
+  func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? {
+    if type == NSPasteboard.PasteboardType.string {
       let timeString = DateFormatter.localizedString(from: timestamp,
                                                                dateStyle: .none,
                                                                timeStyle: .medium)
diff --git a/src/Tulsi/UIRuleEntry.swift b/src/Tulsi/UIRuleEntry.swift
index 18dc565..f93ebb2 100644
--- a/src/Tulsi/UIRuleEntry.swift
+++ b/src/Tulsi/UIRuleEntry.swift
@@ -18,15 +18,15 @@
 /// Wraps a TulsiGenerator::RuleInfo with functionality to allow it to track selection and be
 /// accessed via bindings in the UI.
 class UIRuleInfo: NSObject, Selectable {
-  dynamic var targetName: String? {
+  @objc dynamic var targetName: String? {
     return ruleInfo.label.targetName
   }
 
-  dynamic var type: String {
+  @objc dynamic var type: String {
     return ruleInfo.type
   }
 
-  dynamic var selected: Bool = false {
+  @objc dynamic var selected: Bool = false {
     didSet {
       if !selected { return }
       let linkedInfos = linkedRuleInfos.allObjects as! [UIRuleInfo]
diff --git a/src/Tulsi/UISelectableOutlineViewNode.swift b/src/Tulsi/UISelectableOutlineViewNode.swift
index 2f46e58..3a4b1d5 100644
--- a/src/Tulsi/UISelectableOutlineViewNode.swift
+++ b/src/Tulsi/UISelectableOutlineViewNode.swift
@@ -23,19 +23,19 @@
 class UISelectableOutlineViewNode: NSObject {
 
   /// The display name for this node.
-  let name: String
+  @objc let name: String
 
   /// The object contained by this node (only valid for leaf nodes).
   var entry: Selectable? {
     didSet {
       if let entry = entry {
-        state = entry.selected ? NSOnState : NSOffState
+        state = entry.selected ? NSControl.StateValue.on.rawValue : NSControl.StateValue.off.rawValue
       }
     }
   }
 
   /// This node's children.
-  var children: [UISelectableOutlineViewNode] {
+  @objc var children: [UISelectableOutlineViewNode] {
     return _children
   }
   private var _children = [UISelectableOutlineViewNode]()
@@ -44,29 +44,29 @@
   weak var parent: UISelectableOutlineViewNode?
 
   /// This node's checkbox state in the UI (NSOnState/NSOffState/NSMixedState)
-  dynamic var state: Int {
+  @objc dynamic var state: Int {
     get {
       if children.isEmpty {
-        return (entry?.selected ?? false) ? NSOnState : NSOffState
+        return (entry?.selected ?? false) ? NSControl.StateValue.on.rawValue : NSControl.StateValue.off.rawValue
       }
 
       var stateIsValid = false
-      var state = NSOffState
+      var state = NSControl.StateValue.off
       for node in children {
         if !stateIsValid {
-          state = node.state
+          state = NSControl.StateValue(rawValue: node.state)
           stateIsValid = true
           continue
         }
-        if state != node.state {
-          return NSMixedState
+        if state.rawValue != node.state {
+          return NSControl.StateValue.mixed.rawValue
         }
       }
-      return state
+      return state.rawValue
     }
 
     set {
-      let newSelectionState = (newValue == NSOnState)
+      let newSelectionState = (newValue == NSControl.StateValue.on.rawValue)
       let selected = entry?.selected
       if selected == newSelectionState {
         return
@@ -105,8 +105,8 @@
   // TODO(abaire): Use a custom control to override nextState: such that it's never set to mixed via user interaction.
   func validateState(_ ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>) throws {
     if let value = ioValue.pointee as? NSNumber {
-      if value.intValue == NSMixedState {
-        ioValue.pointee = NSNumber(value: NSOnState as Int)
+      if value.intValue == NSControl.StateValue.mixed.rawValue {
+        ioValue.pointee = NSNumber(value: NSControl.StateValue.on.rawValue as Int)
       }
     }
   }
diff --git a/src/Tulsi/UISourcePath.swift b/src/Tulsi/UISourcePath.swift
index f87c6da..b059c5a 100644
--- a/src/Tulsi/UISourcePath.swift
+++ b/src/Tulsi/UISourcePath.swift
@@ -17,9 +17,9 @@
 
 /// Models a path containing source files and a user selection state.
 class UISourcePath: NSObject, Selectable {
-  dynamic let path: String
-  dynamic var selected: Bool
-  dynamic var recursive: Bool
+  @objc dynamic let path: String
+  @objc dynamic var selected: Bool
+  @objc dynamic var recursive: Bool
 
   init(path: String, selected: Bool = false, recursive: Bool = false) {
     self.path = path
diff --git a/src/Tulsi/XcodeProjectGenerationProgressViewController.swift b/src/Tulsi/XcodeProjectGenerationProgressViewController.swift
index 76f82e8..35424c9 100644
--- a/src/Tulsi/XcodeProjectGenerationProgressViewController.swift
+++ b/src/Tulsi/XcodeProjectGenerationProgressViewController.swift
@@ -18,10 +18,10 @@
 
 /// Models a Tulsi generator action whose progress should be monitored.
 class ProgressItem: NSObject {
-  dynamic let label: String
-  dynamic let maxValue: Int
-  dynamic var value: Int
-  dynamic var indeterminate: Bool
+  @objc dynamic let label: String
+  @objc dynamic let maxValue: Int
+  @objc dynamic var value: Int
+  @objc dynamic var indeterminate: Bool
 
   init(notifier: AnyObject?, values: [AnyHashable: Any]) {
     let taskName = values[ProgressUpdatingTaskName] as! String
@@ -45,7 +45,7 @@
     NotificationCenter.default.removeObserver(self)
   }
 
-  func progressUpdate(_ notification: Notification) {
+  @objc func progressUpdate(_ notification: Notification) {
     indeterminate = false
     if let newValue = notification.userInfo?[ProgressUpdatingTaskProgressValue] as? Int {
       value = newValue
@@ -56,7 +56,7 @@
 
 /// Handles generation of an Xcode project and displaying progress.
 class XcodeProjectGenerationProgressViewController: NSViewController {
-  dynamic var progressItems = [ProgressItem]()
+  @objc dynamic var progressItems = [ProgressItem]()
 
   weak var outputFolderOpenPanel: NSOpenPanel? = nil
 
@@ -95,7 +95,7 @@
     }
   }
 
-  func progressUpdatingTaskDidStart(_ notification: Notification) {
+  @objc func progressUpdatingTaskDidStart(_ notification: Notification) {
     guard let values = notification.userInfo else {
       assertionFailure("Progress task notification received without parameters.")
       return
@@ -119,7 +119,7 @@
     panel.canChooseFiles = false
     panel.beginSheetModal(for: view.window!) {
       let url: URL?
-      if $0 == NSFileHandlingPanelOKButton {
+      if $0.rawValue == NSFileHandlingPanelOKButton {
         url = panel.url
       } else {
         url = nil
diff --git a/src/Tulsi/main.swift b/src/Tulsi/main.swift
index 557c66a..83cc439 100644
--- a/src/Tulsi/main.swift
+++ b/src/Tulsi/main.swift
@@ -59,7 +59,7 @@
     } catch HeadlessModeError.invalidBazelPath {
       print("The path to the bazel binary is invalid")
       exit(14)
-    } catch HeadlessModeError.generationFailed() {
+    } catch HeadlessModeError.generationFailed {
       print("Xcode project generation failed")
       exit(15)
     } catch HeadlessModeError.invalidWorkspaceRootOverride {
diff --git a/src/TulsiGenerator/BazelQueryInfoExtractor.swift b/src/TulsiGenerator/BazelQueryInfoExtractor.swift
index 7e0a73d..5badd01 100644
--- a/src/TulsiGenerator/BazelQueryInfoExtractor.swift
+++ b/src/TulsiGenerator/BazelQueryInfoExtractor.swift
@@ -253,7 +253,7 @@
   private func extractRuleInfosWithRuleInputsFromBazelXMLOutput(_ bazelOutput: Data) -> [RuleInfo: Set<BuildLabel>]? {
     do {
       var infos = [RuleInfo: Set<BuildLabel>]()
-      let doc = try XMLDocument(data: bazelOutput, options: 0)
+      let doc = try XMLDocument(data: bazelOutput, options: XMLNode.Options(rawValue: 0))
       let rules = try doc.nodes(forXPath: "/query/rule")
       for ruleNode in rules {
         guard let ruleElement = ruleNode as? XMLElement else {
@@ -320,7 +320,7 @@
 
   private func extractSourceFileLabelsFromBazelXMLOutput(_ bazelOutput: Data) -> Set<BuildLabel>? {
     do {
-      let doc = try XMLDocument(data: bazelOutput, options: 0)
+      let doc = try XMLDocument(data: bazelOutput, options: XMLNode.Options(rawValue: 0))
       let fileLabels = try doc.nodes(forXPath: "/query/source-file/@name")
       var extractedLabels = Set<BuildLabel>()
       for labelNode in fileLabels {
diff --git a/src/TulsiGenerator/PBXObjects.swift b/src/TulsiGenerator/PBXObjects.swift
index 1fbec9d..acb2721 100644
--- a/src/TulsiGenerator/PBXObjects.swift
+++ b/src/TulsiGenerator/PBXObjects.swift
@@ -1092,7 +1092,7 @@
   var targetByName = [String: PBXTarget]()
 
   /// List of all targets.
-  var allTargets: LazyMapCollection<Dictionary<String, PBXTarget>, PBXTarget> {
+  var allTargets: Dictionary<String, PBXTarget>.Values {
     return targetByName.values
   }
 
diff --git a/src/TulsiGenerator/RuleEntry.swift b/src/TulsiGenerator/RuleEntry.swift
index 1f67449..2b1f87e 100644
--- a/src/TulsiGenerator/RuleEntry.swift
+++ b/src/TulsiGenerator/RuleEntry.swift
@@ -28,7 +28,7 @@
   }
 
   public var debugDescription: String {
-    return "\(type(of: self))(\(label) \(type))"
+    return "\(Swift.type(of: self))(\(label) \(type))"
   }
 
   init(label: BuildLabel, type: String, linkedTargetLabels: Set<BuildLabel>) {
@@ -38,7 +38,7 @@
   }
 
   func equals(_ other: RuleInfo) -> Bool {
-    guard type(of: self) == type(of: other) else {
+    guard Swift.type(of: self) == Swift.type(of: other) else {
       return false
     }
     return self.type == other.type && self.label == other.label
@@ -295,7 +295,7 @@
     if let productType = self.productType {
       return productType
     }
-    return BuildTypeToTargetType[self.type]
+    return RuleEntry.BuildTypeToTargetType[self.type]
   }()
 
   /// Returns the value to be used as the Xcode SDKROOT for the build target generated for this
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift
index 27582eb..b098229 100644
--- a/src/TulsiGenerator/XcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -298,8 +298,8 @@
       cachedDefaultSwiftVersion = XcodeProjectGenerator.DefaultSwiftVersion
       return XcodeProjectGenerator.DefaultSwiftVersion
     }
-    cachedDefaultSwiftVersion = stdout.substring(with: match.rangeAt(1))
-    return stdout.substring(with: match.rangeAt(1))
+    cachedDefaultSwiftVersion = stdout.substring(with: match.range(at: 1))
+    return stdout.substring(with: match.range(at: 1))
   }
 
   /// Encapsulates information about the results of a buildXcodeProjectWithMainGroup invocation.
@@ -712,7 +712,7 @@
       let xmlDocument = scheme.toXML()
 
 
-      let data = xmlDocument.xmlData(withOptions: Int(XMLNode.Options.nodePrettyPrint.rawValue))
+      let data = xmlDocument.xmlData(options: XMLNode.Options(rawValue: XMLNode.Options.RawValue(Int(XMLNode.Options.nodePrettyPrint.rawValue))))
       try writeDataHandler(url, data)
     }
 
@@ -794,7 +794,7 @@
       let xmlDocument = scheme.toXML()
 
 
-      let data = xmlDocument.xmlData(withOptions: Int(XMLNode.Options.nodePrettyPrint.rawValue))
+      let data = xmlDocument.xmlData(options: XMLNode.Options(rawValue: XMLNode.Options.RawValue(Int(XMLNode.Options.nodePrettyPrint.rawValue))))
       try writeDataHandler(url, data)
     }
 
diff --git a/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift b/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
index 9854523..0421e70 100644
--- a/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/XcodeProjectGeneratorTests.swift
@@ -92,7 +92,7 @@
                  extensionType: String? = nil,
                  productType: PBXTarget.ProductType? = nil) -> BuildLabel {
       let label = BuildLabel(labelName)
-      mockExtractor.labelToRuleEntry[label] = type(of: self).makeRuleEntry(label,
+      mockExtractor.labelToRuleEntry[label] = Swift.type(of: self).makeRuleEntry(label,
                                                                            type: type,
                                                                            attributes: attributes,
                                                                            weakDependencies: weakDependencies,
@@ -186,7 +186,7 @@
                  weakDependencies: Set<BuildLabel>? = nil,
                  productType: PBXTarget.ProductType? = nil) -> BuildLabel {
       let label = BuildLabel(labelName)
-      mockExtractor.labelToRuleEntry[label] = type(of: self).makeRuleEntry(label,
+      mockExtractor.labelToRuleEntry[label] = Swift.type(of: self).makeRuleEntry(label,
                                                                              type: type,
                                                                              attributes: attributes,
                                                                              weakDependencies: weakDependencies,
@@ -363,7 +363,7 @@
 
   override func createDirectory(at url: URL,
                                      withIntermediateDirectories createIntermediates: Bool,
-                                     attributes: [String:Any]?) throws {
+                                     attributes: [FileAttributeKey:Any]?) throws {
     if allowedDirectoryCreates.contains(url.path) { return }
     throw NSError(domain: "MockFileManager: Directory creation disallowed",
                   code: 0,
@@ -372,7 +372,7 @@
 
   override func createDirectory(atPath path: String,
                                       withIntermediateDirectories createIntermediates: Bool,
-                                      attributes: [String:Any]?) throws {
+                                      attributes: [FileAttributeKey:Any]?) throws {
     if allowedDirectoryCreates.contains(path) { return }
     throw NSError(domain: "MockFileManager: Directory creation disallowed",
                   code: 0,
@@ -399,7 +399,7 @@
     return mockContent[path]
   }
 
-  override func createFile(atPath path: String, contents data: Data?, attributes attr: [String : Any]? = nil) -> Bool {
+  override func createFile(atPath path: String, contents data: Data?, attributes attr: [FileAttributeKey : Any]? = nil) -> Bool {
     if writeOperations.keys.contains(path) {
       fatalError("Attempting to overwrite an existing file at \(path)")
     }