Taming Nsdocument Too Agreement Who's Boss: Creating A Unproblematic Macos Text Editor (Swift 3, Xcode Viii Beta 6)

Looking at Apple's diagrams inward their documentation nosotros meet that NSDocumentController is boss of NSDocument, which inward plough is boss of NSWindowController together with this leads to the document window beingness displayed. Yup, but what is actually happening together with what does this hateful inward price of code?

Creating the project

As with other apps, create a novel projection together with choose macOS Cocoa every bit the type:

And having clicked next, brand certain you lot choose the "Create Document-Based Application" checkbox:


Navigating the Files

When a document-based app is created amongst the familiar AppDelegate together with ViewController files nosotros convey Document.swift every bit well. This concluding shape file providing a subclass of NSDocument.

The most of import matter to banknote origin of all is that:
  1. the ViewController shape does not ain or create an instance of our NSDocument subclass (i.e. Document)
  2. the Document shape does not ain or create an instance of the NSViewController subclass (i.e. ViewController)
So how does this whole NSDocument matter piece of occupation if neither shape instantiates the other? Well, within the Document shape nosotros uncovering the code where things are setup:
override func makeWindowControllers() {     // Returns the Storyboard that contains your Document window.     allow storyboard = NSStoryboard(name: "Main", bundle: nil)     allow windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as! NSWindowController     self.addWindowController(windowController) }
And inward the Storyboard nosotros meet how everything is nested:

The Window Controller that is instantiated inward makeWindowControllers contains a Window that inward plough contains a View Controller.

Adding a Text View

We tin move add together a text persuasion to the View Controller past times dragging ane out inward the storyboard, adding constraints (using the triangular add together missing constraints push at the bottom correct of the storyboard) together with linking to the ViewController shape every bit an outlet (and naming it for the purposes of this tutorial: textView). But hither nosotros striking the origin issue: how practise nosotros instruct a reference to the text contained inward the Text View that nosotros simply added from within the Document class?

This happens past times adding ii lines of code to the makeWindowsController method:
let vc = windowController.contentViewController as! ViewController vc.textView.string = string 
together with also a shape belongings to the Document shape every bit well:
var string = "" 
The string belongings is added for loading together with creating novel files. The argue for this is because at initialisation the Text View hasn't been created together with thus if nosotros were to move past times the information received from the NSDocument read method straight into the text persuasion of the persuasion controller together with thus a crash would occur, thus nosotros position the text into a string origin together with and thus instruct out it at that spot until the window appears because it is alone at this phase that the persuasion controller together with its persuasion are inward place.

Now nosotros are create to fulfil the reading together with writing of information inward our Document.

Reading File Data

For simplicity I'm going to assume that we'll alone hold upwards receiving UTF8 encoded strings for now.
override func read(from data: Data, ofType typeName: String) throws {     if allow sec = String(data: data, encoding: String.Encoding.utf8) {         string = sec     } }
The information is transformed into a string together with and thus saved to the document string property. As explained this string is non sent direct to the text persuasion otherwise it would crash the app.

Writing File Data

Writing file information is non also much problem either, nosotros simply require a reference to the persuasion controller together with its text persuasion together with and thus to supply the string within it every bit Data. The NSDocumentController does the balance (and nosotros don't fifty-fifty require to worry almost subclassing or instantiating it).
override func data(ofType typeName: String) throws -> Data {     if allow vc = self.windowControllers[0].contentViewController as? ViewController {         supply vc.textView.string?.data(using: String.Encoding.utf8) ?? Data()     }        else {         supply Data()     } }
As nosotros meet from the opening diagram the NSDocument subclass creates an NSWindowController, which inward plough displays a window. Hence a reference to the window together with its persuasion controller is ever possible to obtain. But it should hold upwards noted that nosotros are assuming hither that at that spot is alone ane window controller (NSWindowController) present. If the app is to a greater extent than complex together with at that spot is argue to believe that this is non the illustration together with thus this needs to hold upwards negotiated.

Document Class (NSDocument subclass)

The entire code for the Document shape looks similar this:
import Cocoa  shape Document: NSDocument {     var string = ""              override shape func autosavesInPlace() -> Bool {         supply truthful     }      override func makeWindowControllers() {         // Returns the Storyboard that contains your Document window.         allow storyboard = NSStoryboard(name: "Main", bundle: nil)         allow windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as! NSWindowController         self.addWindowController(windowController)                  allow vc = windowController.contentViewController as! ViewController         vc.textView.string = string         }      override func data(ofType typeName: String) throws -> Data {         if allow vc = self.windowControllers[0].contentViewController as? ViewController {             supply vc.textView.string?.data(using: String.Encoding.utf8) ?? Data()         }            else {             supply Data()         }     }      override func read(from data: Data, ofType typeName: String) throws {         if allow sec = String(data: data, encoding: String.Encoding.utf8) {             string = sec         }     }   } 

ViewController Class (NSViewController subclass)

The ViewController itself is stupidly uncomplicated inward this example:
import Cocoa  shape ViewController: NSViewController {      @IBOutlet var textView: NSTextView!  } 

Testing the app

Believe it or non the app is straight off a performance text editor that tin move hold upwards used to opened upwards together with salve files created within the app together with past times adding an Imported UTI type (to Targets -> App -> Info) nosotros tin move also opened upwards text files created elsewhere:
The information required to consummate the imported UTI types tin move hold upwards constitute inward the Apple Documentation. Note: for this to fully role we'd require to update the code hither to handgrip the most mutual text formats (currently we're alone supporting UTF8) but I'll instruct out things hither for now.


Comments

Popular posts from this blog

Removing The Index.Php File From Url Inward Codeigniter

What Are The Main Components of a Computer System

Delete Daily Doppler E-Mail Spam From An Iphone [Fix]