В Swift модификатор переменной private
не применяется к классам, которые определены в одном файле, поэтому, если вы поместите определение класса модели в тот же файл, что и ваш подкласс NSDocument, подкласс NSDocument может изменить частную модель как если бы они были общедоступными, но подкласс NSViewController, определенный в другом файле, не будет иметь доступа к приватным переменным модели.
Тогда вы можете сделать частные переменные частично частная, написав:
private(set) var name: String
... что позволит подкласс NSController читать их, но не устанавливать их. Swift синтезирует сеттеры и геттеры для всех ваших переменных (а не только для вычисляемых свойств), а также сообщает Swift, чтобы сделать setter частным.
Я проверил private(set)
с некоторым кодом наблюдателя, и вышеупомянутый сценарий позволит подкласс NSDocument изменить модель, но если подкласс NSViewController пытается изменить модель, Xcode сразу помечает назначения с ошибкой:
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"
}
}
Часть кода осуществлять классы:
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
Тогда, если я раскомментировать строку:
doStuff() {
...
//document.worker.name = "Jenny"
...
}
Xcode сразу флаги, как ошибка.
Примечание. В структурах нет проблем, поскольку объявление их как 'private (set)' внутри документа выполняет задание. С классами, хотя 'private (set)' только предотвращает изменение ссылки извне документа, но не содержимое объекта. – George