2017-06-21 6 views
2

Wie erhalten Sie eine Referenzeigenschaft, um eine Objektbeobachtung auszulösen?swift property observer auf Referenzeigenschaft

Um mein Problem zu demonstrieren, schrieb ich ein einfaches MVC-Programm mit einem Knopf und einem Etikett. Die Schaltfläche erhöht einen Zähler im Modell und zeigt den Wert des Zählers in der Beschriftung im Ansichtscontroller an.

Das Problem ist, dass das Zählerschrittweite (in dem Modell) nicht die didSet Beobachter auslösen (im View-Controller)

Hier ist die Modelldatei:

import Foundation 

class MvcModel { 
    var counter: Int 
    var message: String 

    init(counter: Int, message: String) { 
     self.counter = counter 
     self.message = message 
    } 
} 

// create instance 
var model = MvcModel(counter: 0, message: "") 

// counting 
func incrementCounter() { 
    model.counter += 1 
    model.message = "Counter Value: \(model.counter)" 
    //print(model.message) 
} 

Hier ist die View-Controller Datei:

import Cocoa 

class ViewController: NSViewController { 

    let model1 = model 

    var messageFromModel = model.message { 
     didSet { 
      updateDisplayCounterLabel() 
     } 
    } 

    // update Label 
    func updateDisplayCounterLabel() { 
     DisplayCounterLabel.stringValue = model1.message 
    } 

    // Label 
    @IBOutlet weak var DisplayCounterLabel: NSTextField! { 
     didSet { 
      DisplayCounterLabel.stringValue = "counter not started" 
     } 
    } 

    // Button 
    @IBAction func IncrementButton(_ sender: NSButton) { 
     incrementCounter() 
     print("IBAction: \(model1.message)") 
    } 
} 

ich denke, das Problem Eigenschaft verweist verknüpft ist (wie ich in der Lage gewesen, dieses Programm Arbeit mit einem Modell auf einer Struktur basiert zu machen).

Ich würde mich freuen, wenn jemand mir sagen könnte, wie man mit Immobilienbeobachtern und Referenz Eigentum umgehen und diese Art von MVC arbeiten, wie ich es in realen Programmen verwenden will.

+0

Bitte senden Lösungen Antworten nicht als Updates für Ihre Frage. Dies soll zukünftigen Besuchern helfen, Verwirrung zu verstehen und zu vermeiden. – Bugs

Antwort

1

Sie einen Delegierten schaffen könnte für MvcModel

protocol MvcModelDelegate { 
    func didUpdateModel(counter:Int) 
} 

Sie als nächstes einen Delegaten Eigenschaft MvcModel hinzufügen

class MvcModel { 
    var counter: Int { 
     didSet { 
      delegate?.didUpdateModel(counter: counter) 
     } 
    } 

    var message: String 
    var delegate: MvcModelDelegate? 

    init(counter: Int, message: String) { 
     self.counter = counter 
     self.message = message 
    } 
} 

dann machen Sie die ViewController Klasse MvcModelDelegate entsprechen und schließlich setzen Sie model.delegate = self in die viewDidLoad

class Controller: UIViewController, MvcModelDelegate { 

    let model = MvcModel(counter: 0, message: "hello") 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.model.delegate = self 
    } 

    func didUpdateModel(counter: Int) { 
     print("new value for counter \(counter)") 
    } 

} 
+0

@Noam Ich habe sowohl das Modell als auch die ViewController-Datei gemäß Ihren Vorschlägen bearbeitet. Ich bin nicht vertraut mit Protokoll und delegiere (da ich gerade mit der Programmierung anfange). Ich bin mir also nicht sicher, ob ich die richtigen Änderungen vorgenommen habe. In jedem Fall wird das Programm kompiliert, aber das Label wird nicht aktualisiert und die Konsole zeigt nur IBAction: Hallo an. Ich muss zu meinen Büchern zurückkehren und die Logik verstehen. –

+0

@ C.Merger Mein Code war nur ein Beispiel. Sie müssen 'print (" new value for counter \ (counter) ")' durch etwas wie 'self.myTextLabel.text = counter.description' ersetzen. –

+0

@Noam Ja, das habe ich verstanden. Es sieht so aus, als ob die Funktion didUpdateModel nicht aufgerufen wird, wenn der Zähler aktualisiert wird. –

0

Falls jemand hier interessiert ist, ist der Code wie von Noam vorgeschlagen.

Modelldatei:

import Foundation 

    protocol MvcModelDelegate { 
     func didUpDateModel(message: String) 
    } 

    class MvcModel { 
     var counter: Int 
     var message: String { 
      didSet { 
       delegate?.didUpDateModel(message: message) 
      } 
     } 
     var delegate: MvcModelDelegate? 

     init(counter: Int, message: String) { 
      self.counter = counter 
      self.message = message 
     } 
    } 

    // create instance 
    var model = MvcModel(counter: 0, message: "") 

    // counting 
    func incrementCounter() { 
     model.counter += 1 
     model.message = "Counter Value: \(model.counter)" 
    } 
} 

-View-Controller-Datei

import Cocoa 

class ViewController: NSViewController, ModelDelegate { 
    // communication link to the model 
    var model1 = model 
    var messageFromModel = messageToLabel 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.model1.delegate = self 
    } 

    // update display 
    func didUpdateModel(message: String) { 
     //self.Label1.stringValue = model1.message 
     self.Label1.stringValue = messageFromModel 
    } 

    // Label 
    @IBOutlet weak var Label1: NSTextField! { 
     didSet { 
      Label1.stringValue = " counter not started" 
     } 
    } 

    // Button 
    @IBAction func testButton(_ sender: NSButton) { 
     incrementCounter() 
    }  
} 
+0

@Noam - Ich habe versucht, das Modell zu modifizieren, um es von einer Klasse in eine Struktur zu verschieben und dabei einige Anpassungen in der Modelldatei vorzunehmen (keine Änderung in der View-Controller-Datei). Sobald ich die Klasse durch struct ändere, funktioniert das Programm nicht mehr. Tatsächlich sieht es so aus, als würde der "delegate? .didUpdateModel (message: message)" nicht ausgeführt, da der Delegate-Wert gleich null ist.Ich vermute, das Problem ist, dass ich die Delegate-Eigenschaft nicht korrekt deklariere/initialisiere. Was würden Sie vorschlagen, das zu korrigieren? Irgendeine Idee von einem Buch, das diese Themen in Details und Klarheit behandelt? –