Using the MVC approach for iOS app development, I would like to observe changes to the model by posting to the NotificationCenter
. For my example, the Person.swift
model is:
class Person {
static let nameDidChange = Notification.Name("nameDidChange")
var name: String {
didSet {
NotificationCenter.default.post(name: Person.nameDidChange, object: self)
}
}
var age: Int
var gender: String
init(name: String, age: Int, gender: String) {
self.name = name
self.age = age
self.gender = gender
}
}
The view controller that observes the model is shown below:
class ViewController: UIViewController {
let person = Person(name: "Homer", age: 44, gender: "male")
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ageLabel: UILabel!
@IBOutlet weak var genderLabel: UILabel!
@IBOutlet weak var nameField: UITextField!
@IBOutlet weak var ageField: UITextField!
@IBOutlet weak var genderField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = person.name
ageLabel.text = String(person.age)
genderLabel.text = person.gender
NotificationCenter.default.addObserver(self,
selector: #selector(self.updateLabels),
name: Person.nameDidChange, object: nil)
}
@IBAction func updatePerson(_ sender: Any) {
guard let name = nameField.text, let age = ageField.text, let gender = genderField.text else { return }
guard let ageNumber = Int(age) else { return }
person.name = name
person.age = ageNumber
person.gender = gender
}
@objc func updateLabels() {
nameLabel.text = person.name
ageLabel.text = String(person.age)
genderLabel.text = person.gender
}
}
The example app works as follows:
- Enter a name, age, and gender in the text fields
- Press the
updatePerson
button to update the model from the text field values - When the model is updated, the notification observer calls the
updateLabels
function to update the user interface.
This approach requires the person.name
to be set last otherwise the updatePerson
button must be pressed twice to update the entire user interface. And since I'm only observing one property, the notification does not represent the entire class. Is there a better way to observe changes of models (a class or struct) in Swift?
Note - I am not interested in using RxSwift for this example.