1

I have three classes that share the same instance of an NSObject subclass.

All those three classes can modify that shared instance attributes and, when that happen, that shared instance must notify all three other classes that X variable has changed.

This is the perfect scenario to use KVO, but I think that it is very inconsistent code with a lot of hardcoded strings, thus no compile time warning or checking occurs, it is difficult to get stacktrace when something goes wrong, in case of refactoring code it is a headache to change everything and pray to not forget anything, remove observers manually when deallocating, repeat a lot of code by adding same observers to all classes etc.

Due to that reasons, I thought that delegates may be a good solution to the majority (if not all) of those problems. Easy to implement, very clear and documented, if something change the compiler tells you about it, no need to manually set to nil anything, no need to have hardcoded strings, obvious stracktrace when something goes wrong etc.

My delegate approach would be overriding all variables' setters that I want to be listening to their changes and call the delegate right there so that all classes can know about that change.

What do you think about this approach?

Thank you in advance!

Leeroy Jenkins
  • 253
  • 2
  • 6
  • The shared instance subclass would have just one protocol with `n` optional methods. The rest of the classes would have to implement that protocol to be able to listen to the shared instance changes. – Leeroy Jenkins May 25 '17 at 14:29
  • Have you considered using NotificationCenter for multiple notifications? – Solomiya May 25 '17 at 14:36
  • `NSNotificationCenter` is very similar to `KVO`, but `KVO` is only used to control variables, and that is what I need. So the problems with `NSNotificationCenter` are **exactly** the same as those when using `KVO`: hardcoded strings, headache when refactoring, undocumented, repeating code etc... – Leeroy Jenkins May 25 '17 at 14:39

1 Answers1

0

While you are entirely correct, you will need hard-coded strings for the keypaths with KVO, I can speak anecdotally, working on several huge applications it rarely is an issue.

The delegate solution would work, but then you'd need to keep track of the delegates (and in your case, it sounds like you would need to keep track of an array of delegates). The way you work with this would be similar to how you would register/unregister with KVO anyways.

The problem your describing is precisely the problem the Observer pattern is supposed to solve, and Cocoa has given you a build-in solution to the pattern

What I'd recommend (most of this you probably know):
1) A extern constant for the keyPath, that all 3 classes can use
2) When one of your observers receive the reference to the object, register the observer with -addObserver:...
3) Make sure you properly call -removeObserver:...
4) In -observeValueForKeyPath:..., compare the keypath to your const, and put your handling in there

But as you mentioned, the main issue that could come up is if the keyPath changes. Your code will still compile, and you won't necessarily catch the issue immediately at runtime.

If that is a genuine concern you could write a wrapper method that calls -addObserver:... but first checks if the receiver responds to the keyPath argument.

Though I've never done this, and as I mentioned I never really this keyPath issue with KVO anyways. Normally if somebody is going in and renaming a keyPath, they would do a workspace search and see the hard-coded string would need to be changed as well

Anyways to summarize, I'd personally prefer the KVO solution over the delegate notification solution, but ultimately you're right in that you could potentially miss bugs w/ KVO

A O
  • 5,516
  • 3
  • 33
  • 68
  • Thank you very much for the answer! After doing some research I decided to use `delegates` because I think that everything ends up more tied. As you say, it is an array of delegates but I am using a `NSHashTable` initialised as `weakObjectsHashTable` so that I do not need to call the KVO's `-removeObserver:...` equivalent. More information here: https://stackoverflow.com/a/23671452/7843625. And after doing some tests, I saw that performing delegates is faster than sending notifications using `KVO`. Nanoseconds difference but there it is! hahah – Leeroy Jenkins Jun 01 '17 at 14:29
  • Cool! Thanks for the reply, I actually never heard of `NSHashTable` even. Though I'm confused a little because I always thought HashTable == Dictionary, AKA there's key/value pairs, but based off that linked answer it looks like you can just insert objects into it just like you would an array? And if that's the case, why not use an Array? Do `NSArrays` create strong references to the objects it contain? – A O Jun 01 '17 at 14:56
  • As you say, `NSArray` creates strong references of the objects it contains. There would not be any problem of the usage of `NSArray` but I would have to take care about removing that references before deallocating the `NSObject`. I am not a pro of the `NSHashTable` so refer to the Apple documentation for more information: https://developer.apple.com/reference/foundation/nshashtable. And yes, it behaves like an `NSArray`. In fact, I **think** that it subclasses from `NSSet`. – Leeroy Jenkins Jun 01 '17 at 16:21