Reputation: 491
After looking at various answers to this question, I haven't found once that fits the exact scenario I am in.
Quite simply, I create a UILabelClass as such:
class pointsLabel: UILabel {
override func willMove(toSuperview newSuperview: UIView?) {
text = points
// Somehow watch UpdateChecker and update text when change
}
}
And have a UpdateChecker NSObject that is told to run when the app launches:
class UpdateChecker: NSObject {
func watchForUpdates () {
receivesUpdateFromServer {
points = pointUpdateFromServer
}
}
}
The pointsLabel class is assigned to various UILabels in interface builder on different view controllers.
How can I best and most efficiently get the pointsLabel to update it's text when the UpdateChecker receives an update? If I use the NSNotification method the problem is that every time a View loads with the label, another notification observer gets registered, and doesn't get removed when the label disappears.
Upvotes: 0
Views: 333
Reputation: 173
You can use property observers for the same. Make a computed property like below:
var updatedValue = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
scoreLabel is your label which automatically updates when score receives any changes. You don't need to go with NSNotification observers. You can access score property from class which receives updates. You can go through this link to get more clear understanding for property observers https://www.swiftbysundell.com/articles/property-observers-in-swift/
Upvotes: 0
Reputation: 437372
You said:
The
UILabel
can be displayed in different view controllers, so I can't tell it to register aNSNotification
observer on load because that means every time the label is loaded it registers the observer again.
No, this is precisely what you should do for capturing updates to some Int
value that needs to be reflected in multiple view controllers. Sure, every time a view controller is loaded (e.g. viewDidLoad
) you’d add the NotificationCenter
observer, and then remove the observer in deinit
. But adding/removing observers is not an appreciably expensive process, so just do it. It sounds like the logical solution for the problem you describe.
FWIW, this does not seem like a good delegate-protocol candidate if multiple view controllers need to be informed of changes to this object. The delegate-protocol pattern is best used when there is a one-to-one relationship between an object and its delegate. But when you have many different view controllers that would like to be the “delegate”, in turn, then an observer pattern makes a lot more sense.
By the way, you reference something that “constantly receives updates” in conjunction with it being a “user default”. If there’s anything in your question that I’d take a hard look at, it would be the notion of using user defaults to capture something that isn’t really a default, but rather something that is presumably a model object that is frequently changing.
For example, let’s assume that I had defined some custom notification:
extension Notification.Name {
static let didUpdateFoo = Notification.Name(Bundle.main.bundleIdentifier! + ".didUpdateFoo")
}
And when Foo
is updated, you’d do:
NotificationCenter.default.post(name: .didUpdateFoo, object: foo)
Then a view controller that wants to observe this notification would:
private var didReceiveFooObserver: NSObjectProtocol?
override func viewDidLoad() {
super.viewDidLoad()
didReceiveFooObserver = NotificationCenter.default.addObserver(forName: .didUpdateFoo, object: nil, queue: .main) { [weak self] notification in
guard let foo = notification.object as? Int else { return }
self?.fooLabel.text = "\(foo)"
}
}
deinit {
if let token = didReceiveFooObserver {
NotificationCenter.default.removeObserver(token)
}
}
Upvotes: 1