In Swift, the private
variable modifier does not apply to classes which are defined in the same file, so if you put your Model class definition in the same file as your NSDocument subclass, then the NSDocument subclass can change the private Model variables as if they were public, but an NSViewController subclass defined in another file will not have access to the private Model variables.
Then you can make private variables partially private by writing:
private(set) var name: String
...which will allow the NSController subclass to read them, but not set them. Swift synthesizes setters and getters for all your variables (not just computed properties), and that tells Swift to make the setter private.
I tested private(set)
with some observer code, and the above scenario will allow the NSDocument subclass to change the Model, but if the NSViewController subclass tries to change the Model, Xcode immediately flags the assignment with the error:
Cannot assign to the result of this expression
MyDocument.swift:
import Cocoa
class Employee: NSObject {
private(set) var name: String
init(name: String) {
self.name = name
super.init()
}
}
class MyDocument: NSDocument {
dynamic var worker = Employee(name: "Joe")
//...The rest of the NSDocument junk here
}
MyViewController.swift:
import Cocoa
class MyViewController: NSObject {
var document: MyDocument
var IdentifierForThisClass: Int = 0
init(document: MyDocument) {
self.document = document
super.init()
self.document.addObserver(self,
forKeyPath: "worker",
options: .Old | .New,
context: &IdentifierForThisClass
)
}
override func observeValueForKeyPath(
keyPath: String,
ofObject object: AnyObject,
change: [NSObject : AnyObject],
context: UnsafeMutablePointer<Void>) {
println("Observer:")
if context != &IdentifierForThisClass {
println("This Observer message was meant for a parent class!")
super.observeValueForKeyPath(keyPath,
ofObject: object,
change: change,
context: context
)
return
}
var newValue = change[NSKeyValueChangeNewKey] as! Employee
println("\tThe worker has been changed to: \(newValue.name)")
}
func doStuff() {
println("Inside doStuff():")
println("\tThe worker's name is \(document.worker.name)")
//document.worker.name = "Jenny"
}
}
Some code to exercise the classes:
let myDoc = MyDocument()
let viewController = MyViewController(
document: myDoc
)
myDoc.worker = Employee(name: "Jenny")
viewController.doStuff()
--output:--
Observer:
The worker has been changed to: Jenny
Inside doStuff():
The worker's name is Jenny
Then if I uncomment the line:
doStuff() {
...
//document.worker.name = "Jenny"
...
}
Xcode immediately flags that as an error.