Archiving: Document.swift and Employees.swift for Swift 4.2, Xcode 10.1

In the Archiving chapter, these updates of Document.swift and Employees.swift for Swift 4.2, Xcode 10.1 are what worked for me. Hope it helps. cheers.

//
//  Employee.swift
//  RaiseMan
//
//  Created by Nicholas Teissler on 2/20/15.
//  Copyright (c) 2014 Big Nerd Ranch. All rights reserved.
//
//  Updated by Frank on 11/8/18

import Foundation

class Employee: NSObject, NSCoding {
    @objc dynamic var name: String? = "New Employee"
    @objc dynamic var raise: NSNumber? = 0.05
    
    
    // MARK: - NSCoding
    
    func encode(with aCoder: NSCoder) {
        if let name = name { aCoder.encode(name, forKey: "name") }
        if let raise = raise { aCoder.encode(raise, forKey: "raise") }
    }
    
    required init?(coder aDecoder: NSCoder) {
        name = aDecoder.decodeObject(forKey: "name") as! String?
        raise = aDecoder.decodeObject(forKey: "raise") as! NSNumber?
        super.init()
    }
    
    override init() {
        super.init()
    }
    

    
    override func validateValue(_ ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>, forKey inKey: String) throws {
        if raise == nil
        {
            let domain = "UserInputValidationErrorDomain"
            let code = 0
            let userInfo = [NSLocalizedDescriptionKey: "Error, raise is nil"]
            
            throw NSError(domain: domain,
                          code: code,
                          userInfo: userInfo)
        }
    }
}


//
//  Document.swift
//  RaiseMan
//
//  Created by Nicholas Teissler on 2/20/15.
//  Copyright (c) 2014 Big Nerd Ranch. All rights reserved.
//
//  Updated by Frank on 11/8/18

import Cocoa

private var KVOContext: Int = 0

class Document: NSDocument, NSWindowDelegate {
    @IBOutlet weak var tableView: NSTableView!
    @IBOutlet weak var arrayController: NSArrayController!
    
    @objc dynamic var employees: [Employee] = [] {
        willSet {
            for employee in employees {
                stopObservingEmployee(employee: employee)
            }
        }
        didSet {
            for employee in employees {
                startObservingEmployee(employee: employee)
            }
        }
    }
    
    // MARK: - Actions
    
    @IBAction func addEmployee(sender: NSButton) {
        let windowController = windowControllers[0]
        let window = windowController.window!
        
        let endedEditing = window.makeFirstResponder(window)
        if !endedEditing {
            Swift.print("Unable to end editing")
            return
        }
        
        let undo: UndoManager = undoManager!
        
        // Has an edit occurred already in this event?
        if undo.groupingLevel > 0 {
            // Close the last group
            undo.endUndoGrouping()
            // Open a new group
            undo.beginUndoGrouping()
        }
        
        // Create the object
        let employee = arrayController.newObject() as! Employee
        
        // Add it to the array controller's content array
        arrayController.addObject(employee)
        
        // Re-sort (in case the use has sorted a column) 
        arrayController.rearrangeObjects()
        
        // Get the sorted array
        let sortedEmployees = arrayController.arrangedObjects as! [Employee]
        
        // Find the object just added
        let row = sortedEmployees.index(of: employee)!
        
        // Begin the edit in the first column
        Swift.print("starting edit of \(employee) in row \(row)")
        tableView.editColumn(0, row: row, with: nil, select: true)
    }
    
    // MARK: - Accessors
    
    @objc func insertObject(_ employee: Employee, inEmployeesAtIndex index: Int) {
        Swift.print("adding \(employee) to the employees array")    // since method is converted to ObjC, need to use 'Swift.print', instead of 'print'
        
        // Add the inverse of this operation to the undo stack
        let undo: UndoManager = undoManager!
        (undo.prepare(withInvocationTarget: self) as AnyObject).removeObject(fromEmployeesAtIndex: employees.count)
        
        if !undo.isUndoing
        {
            undo.setActionName("Add Person")
        }
        
        employees.append(employee)
    }
    
    
    @objc func removeObject(fromEmployeesAtIndex index: Int) {
        let employee: Employee = employees[index]
        
        Swift.print("removing \(employee) from the employees array")
        
        // Add the inverse of this operation to the undo stack
        let undo: UndoManager = undoManager!
        (undo.prepare(withInvocationTarget:self) as AnyObject).insertObject(employee, inEmployeesAtIndex: index)
        
        if !undo.isUndoing
        {
            undo.setActionName("Remove Person")
        }
        
        // Remove the Employee from the array
        employees.remove(at: index)
    }
    
    // MARK: - Key Value Observing
    
    func startObservingEmployee(employee: Employee) {
        employee.addObserver(self, forKeyPath: "name", options: .old, context: &KVOContext)
        employee.addObserver(self, forKeyPath: "raise", options: .old, context: &KVOContext)
    }
    
    func stopObservingEmployee(employee: Employee) {
        employee.removeObserver(self, forKeyPath: "name", context: &KVOContext)
        employee.removeObserver(self, forKeyPath: "raise", context: &KVOContext)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if context != &KVOContext
        {
            // If the context does not match, this message
            // must be intended for our superclass.
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
        
        var oldValue: AnyObject? = change![NSKeyValueChangeKey.oldKey] as AnyObject
        if oldValue is NSNull
        {
            oldValue = nil
        }
        
        let undo: UndoManager = undoManager!
        Swift.print("oldValue = \(String(describing: oldValue))")
        
        (undo.prepare(withInvocationTarget: object!) as AnyObject).setValue(oldValue, forKeyPath: keyPath!)
    }
    
    
    
    // MARK - Lifecycle
    
    override init() {
        super.init()
        // Add your subclass-specific initialization here.

    }


    override class var autosavesInPlace: Bool
    {
        return true
    }
    
    
    override var windowNibName: NSNib.Name?
    {
        // Returns the nib file name of the document
        // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this property and override -makeWindowControllers instead.
        return NSNib.Name("Document")
    }
    
    // MARK: - NSWindowDelegate
    
    func windowWillClose(_ notification: Notification) {
        employees = []
    }
    
    

    override func data(ofType typeName: String) throws -> Data{
        // Insert code here to write your document to data of the specified type, throwing an error in case of failure.
        // Alternatively, you could remove this method and override fileWrapper(ofType:), write(to:ofType:), or write(to:ofType:for:originalContentsURL:) instead.
        
        // NB: FOR FILE LOADING/SAVING, YOU NEED TO CHANGE APP SANDBOX SETTINGS.
        //     ... Under Project > Target > Capabilities > App Sandbox > File Access > User Selected File > "Read/Write"
        
        // End editing
        tableView.window?.endEditing(for: nil)
        
        // Create an NSData object from the employees array
        guard let archive: Data = try? NSKeyedArchiver.archivedData(withRootObject: employees, requiringSecureCoding: false)
        else
        {
            let outError:NSError! = NSError(domain: "Migrator", code: 0, userInfo: [NSLocalizedDescriptionKey : "The file could not be written"])
            throw outError
        }
    
    return archive
    }
    
    override func read(from data: Data, ofType typeName: String) throws {
        // Insert code here to read your document from the given data of the specified type, throwing an error in case of failure.
        // Alternatively, you could remove this method and override read(from:ofType:) instead.
        // If you do, you should also override isEntireFileLoaded to return false if the contents are lazily loaded.
        
        // NB: FOR FILE LOADING/SAVING, YOU NEED TO CHANGE APP SANDBOX SETTINGS.
        //     ... Under Project > Target > Capabilities > App Sandbox > File Access > User Selected File > "Read/Write"
        
        Swift.print("About to read data of type \(typeName).")
        
        guard let archive = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [Employee]?
        else
        {
            let outError: NSError! = NSError(domain: "Migrator", code: 0, userInfo: [NSLocalizedDescriptionKey : "The file could not be read"])
            throw outError
        }
    employees = archive
    }


}