2015-07-24 2 views
0

Я пишу приложение на основе OS X с использованием какао/swift. Пока у меня есть модель, которой управляет подкласс NSDocument. Пользовательские представления управляются настраиваемыми контроллерами представлений, которые обновляют представления, чтобы синхронизировать их с моделью.Защита модели в архитектуре документов (Cocoa/Swift)

Модель-> Контроллер-> просмотр потока информации непросто. У меня есть контролеры просмотра, наблюдающие за документом, и, когда документ изменяется, диспетчеры представлений выполняют свою работу с представлениями. Проблема в том, что в этом процессе объекты модели, очевидно, подвергаются воздействию контроллеров представления, и поэтому контроллеры представлений могут также модифицировать модель, если я захочу (или если я сделаю ошибку).

Я хочу, чтобы документ был единственным, у которого есть «разрешение» для изменения объектов модели. Контроллеры представлений должны иметь доступ только для чтения. Есть ли способ сделать это в Свифт?

Заранее благодарен.

+0

Примечание. В структурах нет проблем, поскольку объявление их как 'private (set)' внутри документа выполняет задание. С классами, хотя 'private (set)' только предотвращает изменение ссылки извне документа, но не содержимое объекта. – George

ответ

0

В 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 сразу флаги, как ошибка.

+0

Это работает только в том случае, если вы определяете объекты модели в том же файле, что и NSDocument, я боюсь ... – George