

Key-Value Observing Considered Harmful - stevenp
http://khanlou.com/2013/12/kvo-considered-harmful/

======
skue
_> KVO all comes through one method_

Yes, and it's annoying to have a long list of if statements. However, there's
a blocks based alternative since iOS4/10.6, and a number of third-party
variations.[1]

 _> KVO is string-ly typed_

That's a big reason why libextobjc's @keypath() macro is so popular.[2]

 _> KVO requires you to handle superclasses yourself_

That's a feature, not a bug. If you use
observeValueForKeyPath:ofObject:change:context: then you need to call super
_just like overriding any other method._ This also gives you the flexibility
to selectively decide to override behavior of your own superclasses.

 _> KVO can crash when deregistering_

Only if you deregister twice. And yes, it really sucks that you can
accidentally deregister the same key path that a superclass deregisters,
resulting in a crash. Much has been written about this issue, and third party
libraries address it.[3]

 _> KVO is a pit of failure_

That's a strong and subjective statement. Yes KVO can be frustrating for new
developers - no argument there. But it does have its place.

 _> KVO is implicit_

Woah, no one (including Apple) is suggesting that apps use KVO for all of
their message passing and dependencies. It has its place, especially for
monitoring changes to Apple's APIs or when multiple observers need to monitor
the same object (again, that's a feature not a bug).

 _> KVO can cause infinite loops_

Your handler should always avoid triggering the same event that triggered it.
That's not unique to KVO.

 _> KVO is the old way_

I remember when Apple introduced it, so I guess that makes me even older!
Actually, Apple's KVO is responsible for some of the newest JS libraries.
SproutCore borrowed many of KVO's ideas,[4] and you may be familiar with one
of SproutCore's notable forks: Ember.js

 _> When is it okay to use KVO?_

Agreed that these are great use cases for KVO. But doesn't this counter the
title of the post? It's certainly not "harmful" to use KVO for these.

[1]
[https://github.com/search?l=Objective-C&q=kvo&source=cc&type...](https://github.com/search?l=Objective-C&q=kvo&source=cc&type=Repositories&s=stars)

[2]
[https://github.com/jspahrsummers/libextobjc/blob/master/exto...](https://github.com/jspahrsummers/libextobjc/blob/master/extobjc/EXTKeyPathCoding.h)

[3] [http://www.mikeash.com/pyblog/friday-qa-2012-03-02-key-
value...](http://www.mikeash.com/pyblog/friday-qa-2012-03-02-key-value-
observing-done-right-take-2.html)

[4]
[http://guides.sproutcore.com/core_concepts_kvo.html](http://guides.sproutcore.com/core_concepts_kvo.html)

------
icodestuff
I disagree with a few points in this article, and can provide clarification on
a few others. The clarifications first:

Bindings don't exist in Cocoa Touch because they're either slow (e.g. computed
properties like @sum) because they're mostly stateless, or memory intensive
because... well, dig into the internals of KVO sometime - there are a huge
number of caches to try to keep things fast. It's not because KVO is a bad
API. Heck, the KVO side of bindings is never exposed at all.

On the topic of infinite loops, yes, you have to be careful not to change an
affecting property within an -observeValue... but it's hardly unknowable what
changes will cause a KVO notification. Indeed, it's an isomorphic problem to
breaking retain cycles, something every Obj-C programmer has to worry about
every day, yes, even with ARC. The information is just stored in a different
place, namely +keyPathsForValuesAffecting<Key> methods, rather than in
property or ivar declarations. One can create a "weak" notification by
removing oneself as an observer in the -observeValue, optionally adding
oneself back at the end.

As for disagreements: KVO is not the old way. NSNotificationCenter and the
delegate pattern predate KVO. Callback blocks don't, and indeed where possible
I'd recommend all of the above over KVO, but it's hardly ancient, and
certainly not "the old way". It's just a different way that allows you to
watch for changes that doesn't require the designers of an API to have
provided hooks for you to do so explicitly.

On its implicitness, I can't agree that it's any more implicit than delegates.
The same criticism that you can't command-click in Xcode to follow the code
flow applies. Same thing with NSNotifications for that matter. That's kind of
the point. If it was all explicit, we wouldn't have the dynamism that all of
these mechanisms provide.

Re: "An important thing to note is that KVO will throw an exception and crash
our app if we try to remove the same observer twice." This is simply untrue.
KVO will throw an exception and crash the app if you try to remove the same
_observance_ twice, but an observance is created each time you call
-addObserver:.... That is, like retain and release, -addObserver: and
-removeObserver: calls need to be balanced. Additionally, the author actually
misses a part where KVO really is broken: "[Using a static context pointer per
observation] helps to make sure that none of our super- or subclasses can
deregister us from being an observer." doesn't actually work. Using
-removeObserver:forKeyPath: will happily remove the first observance it comes
across (the first that was registered, AFAICT, though this isn't documented),
regardless of its context; it's not just a convenience method for
-removeObserver:forKeyPath:context: that passes NULL for the last parameter.

Lastly, it seems quite silly to have a unique context for each object and key
path per class. If they're going to unique the contexts, you don't need to
check objects and key paths. Or, you only need one context per class, and then
only if your inheritance tree does include multiple observing classes. On a
related note, I think the complaint about having to call super if the
superclass implements -observeValue... is ridiculous. This is how any method
that might be implemented at multiple levels of an inheritance tree must be
called. Same thing with a delegate whose superclass also conforms to that
delegate protocol. Or -init. Or -dealloc. Or...

.

All that said, I still generally agree with the conclusions about when to use
KVO, although is #3 is just a subset of #1, and I wouldn't have phrased it as
the author did (see the first paragraph of disagreement). I'd also add #4: Use
KVO when you need the old values as well as the new values of the objects,
and/or need to be notified prior to the value changing. NSNotificationCenter
and delegates can do the same thing, but at the cost of double the number of
methods that need to be written, and you'll have to store the state yourself
if you need the old value at the same time as the new value. That's a lot of
code that gets abstracted away by KVO, particularly if you're observing
multiple key paths on the same object and need all their old and new values.
Code you don't have to write is code you don't have to debug.

------
jheriko
"When trying to be informed of changes on a class that you don’t own, such as
one of Apple’s classes. A classic case of this is observing the contentSize of
a table view. This information can’t be gotten in any other way."

I never like this - platform holders ramming their crap down your throat
basically...

A broader version of this applies to Objective-C as a whole for me... I have
to use it to interact with iOS or OS X in the intended way. There is no other
reason for me to want to use it - the language features are not helpful for
me, the ref counting is dangerous and the performance is horrendous (that last
one is a design tradeoff to be fair - but I don't want to pay for what I don't
use).

~~~
bandushrew
"the ref counting is dangerous"

hmm?

~~~
jheriko
i consider it dangerous because it requires more manual (and error-prone) work
than just doing allocations/deallocations yourself.

i can see the theoretical justification but I am yet to use a system where:

* i do not need to decrement ref counts manually in various situations or by default

* i do not get memory leaks resulting from the above ambiguity

* its easy to debug a leak (because I need to hunt for the right place to decrement the reference count, not just slap it in wherever i want)

coupled with the performance overhead of refcounting i see no benefit to it in
practice - as nice as the theoretical idea is. this could be personal
experience though - i can easily say that i've had more memory leaks from not
understanding a ref counted library than when i manage my own memory - but
that might not be the general case.

~~~
bandushrew
yeah, the problem with these kinds of discussions is that each of us has had
their opinion coloured by their different experiences of software.

Overall, my experience of ref counting as implemented by the Apple frameworks
has been very positive indeed.

My experience of ref counting in other contexts/frameworks has been patchy,
usually depending upon the quality of the developers responsible for it.

The thing I really do like about ref counting is that it is deterministic,
unlike other approaches, ie garbage collection.

------
memracom
Just use Reactive Cocoa.

