By Peng Xie
The other day I came across a bug when I tried to use Key-Value Observing to observe the change of a property in some not-so-modern Objective-C class. The observer was never notified when the property’s value changed. It took me a long time to figure out what was wrong and I just want to share my findings, so you don’t have to be upset should you ever run into a similar situation.
It all started with a simple “@synthesize” statement.
Some background first. In “Adopting Modern Objective-C” document, Apple recommends using properties instead of instance variables (or iVars) in “as many places as possible”. One of the benefits listed is “Auto-synthesized getters and setters”. If you still remember all the “@synthesize” statements in stone-age of Objective-C, I believe you will just love auto-synthesizing feature in modern Objective-C as much as I do. (Almost) No more “@synthesize”! Isn’t that sweet?
Even though synthesizing is no longer required (most of the cases, and usually not even recommended), you can still use it to synthesize a property with a backing iVar (Compiler will create an iVar with the same name of the property if there isn’t one created by developer.) and custom setter and getter. However, if you don’t make your setter KVO-compliant or just simply ignore setter and change backing iVar’s value directly, KVO will obviously fail to observe the change in property’s value.
A well-designed custom setter or a setter created by auto-synthesizing calls “willChangeValueForKey:” and “didChangeValueForKey:” methods at appropriate moments to send observer notifications so that observers that implements KVO methods know when a property is changed. If new value is directly assigned to a backing iVar, the setter is never called and hence there will be no notification sent for KVO. Not only will your own KVO code not work, any framework you may have used in your project that depends on KVO will also not work.
You can find a demo project. In the demo, if a property’s value is modified without using the accessor (setter in this case), KVO won’t be able to observe the change.
TL;DR Listen to Apple and use properties wherever possible.