I am trying to develop an app that includes a StoryBoard with a single NSTextView that I want to use to log app events and user feedback. I load the view from a check box switch from the Main view (the console log view is turned on by default when the app launches). All works well to this point with the app launching and the second view working with the text as expected from the viewDidLoad() function.
The NSViewController class for the console log view is:
class ConsoleLogViewController: NSViewController,NSTextViewDelegate {
@IBOutlet var textViewConsoleLog: NSTextView!
override func viewWillDisappear() {
(representedObject as! NSButton).isEnabled = true
(representedObject as! NSButton).state = NSOffState
}
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
textViewConsoleLog.delegate = self
textViewConsoleLog.string = "All new journal events are logged to this window"
textViewConsoleLog.string?.append("\n")
textViewConsoleLog.string?.append("*********************************************")
textViewConsoleLog.string?.append("\n")
textViewConsoleLog.string?.append("\n")
} // END OF viewDidLoad()
func addLogToConsoleWindow(newLogEntry: String) {
textViewConsoleLog.string? = (newLogEntry)
textViewConsoleLog.string?.append("\n")
} // END OF addLogToConsoleWindow()
} // END OF ConsoleLogViewController
The View is launched from the main view controller (named 'Control' in the image below) using the following function call:
func showConsoleLogView() {
let buttonCall = chkBoxConsoleLog
performSegue(withIdentifier: "sequeConsoleView", sender: buttonCall)
} // END OF showConsoleLogView()
In the main view controller I create an instance of ConsoleLogViewController and then try and use the function addLogToConsoleWindow to append additional log information to the textViewConsoleLog. The relevant snippets of code in the Main view controller are:
let consoleOutputPrintStatement = ConsoleLogViewController() // Create an instance of ConsoleLogViewController to allow logging to the new console window
and
consoleOutputPrintStatement.addLogToConsoleWindow(newLogEntry: "Loading journal files")
However, when i run the app and try to write additional lines of text I get a fatal error: unexpectedly found nil while unwrapping an Optional value
. It is clear that the textViewConsoleLog object is nil and is creating the error.
I assume that the problem is that I am creating another instance of the class and hence I am trying to append additional text to a textViewConsoleLog object that hasn't been initiated (or something like that!).
The app looks like this when it first runs:
So - am I just heading down the wrong road trying to develop a logging function to a console using NSTextView? Or am I close but need a different approach with the NSTextView to make it work? How do I update the text in the NSTextField with relevant strings generated from the other viewControllers?
Any assistance or guidance highly appreciated.
OK - I finally sorted out a solution using NSNotification - which in hindsight was pretty obvious.
The relevant code in the console log view is shown below with the class being set up to receive a notification from the NotificationCenter using the addObserver
method.:
class ConsoleLogViewController: NSViewController,NSTextViewDelegate {
@IBOutlet var textViewConsoleLog: NSTextView!
let controlCentreDidSendConsoleNotification = "TCCEDJ.controlCentreDidSendConsoleNotification"
let controlCentreDidSendConsoleNotificationMessageKey = "TCCEDJ.controlCentreDidSendConsoleNotificationMessageKey"
override func viewWillDisappear() {
(representedObject as! NSButton).isEnabled = true
(representedObject as! NSButton).state = NSOffState
}
override func viewDidLoad() {
super.viewDidLoad()
textViewConsoleLog.delegate = self
textViewConsoleLog.string = "All new journal events are logged to this window"
textViewConsoleLog.string?.append("\n")
textViewConsoleLog.string?.append("*********************************************")
textViewConsoleLog.string?.append("\n")
textViewConsoleLog.string?.append("\n")
// set up notification centre
let notificationCentre = NotificationCenter.default
notificationCentre.addObserver(self, selector: #selector(addLogToConsoleWindow), name: NSNotification.Name(rawValue: controlCentreDidSendConsoleNotification), object: nil)
} // END OF viewDidLoad()
@objc func addLogToConsoleWindow(newLogEntry: NSNotification) {
let userInfo = newLogEntry.userInfo as! [String: String]
let newLogEntryString = userInfo[controlCentreDidSendConsoleNotificationMessageKey]!
textViewConsoleLog.string?.append(newLogEntryString)
textViewConsoleLog.string?.append("\n")
textViewConsoleLog.scrollRangeToVisible(NSMakeRange((textViewConsoleLog.string?.characters.count)! - 1, 0))
} // END OF addLogToConsoleWindow()
} // END OF ConsoleLogViewController
The relevant code in the main view controller is:
// Set up variables to use with notification centre
let controlCentreDidSendConsoleNotification = "TCCEDJ.controlCentreDidSendConsoleNotification"
let controlCentreDidSendConsoleNotificationMessageKey = "TCCEDJ.controlCentreDidSendConsoleNotificationMessageKey"
and
let testLog = [controlCentreDidSendConsoleNotificationMessageKey: "Test log on button push"]
let notificationCentre = NotificationCenter.default
notificationCentre.post(name: NSNotification.Name(rawValue: controlCentreDidSendConsoleNotification), object: self, userInfo: testLog)
All now works with the behaviour that I was looking for.