Reputation: 15247
In Swift, I have a data model that uses an array of items that are displayed in a table view.
The data model can be changed any time by various sources, and I want to reload the table view when it is changed.
This is very simple if the array of items itself is changed, e.g. by assigning a new array to the data model’s array property: The setter could trigger the reload, e.g. by KVO.
If, however, only an array element (an item) is changed by changing one of its properties, the table view reload had to be triggered by the setter of the item’s property.
This would be possible if each item has a reference back to the data model that stored the array of items: Using this reference, the data model could be notified of an item’s change, and trigger the reload of the table view. However, I think it is not a good programming style if an array element had a reference to its array.
An alternative thus were if the array elements (the items) could only be changed by the data model itself. In this case the setters of the item’s properties should be available only for the data model.
One way to achieve this is to define the user model class and the item class in the same file, and declare the item’s property setters as fileprivate
. Then, only the data model could change the item’s properties.
But to have both classes defined in one file only for this reason seems to me not very elegant.
Is there a more straightforward way to handle the situation?
Upvotes: 1
Views: 1182
Reputation: 14824
One other solution is to write your own simple observation system using protocols. The advantage is that it keeps everything more loosely coupled, and can easily be expanded for future use:
class MyElement {
var property = "Test" {
didSet {
guard property != oldValue else { return }
for observer in observers {
observer.didChangeProperty(element: self)
}
}
}
var observers: [MyElementObserver] = []
}
protocol MyElementObserver {
func didChangeProperty(element: MyElement)
}
extension MyElementObserver {
func didChangeProperty(element: MyElement) {}
}
You can then make your view conform to this protocol and handle adding itself to the observers
array for each element, or you can go the probably-cleaner route and make a MyDataModelObserver
protocol as well, then making your data model observe its elements and pass these notifications on to its observers (namely, the view).
Upvotes: 3