Jul 17 2010

Defects of KVO

KVO(Key-Value Observing) is a very nice programming facility from Apple. Working together with KVC(Key-Value Coding), it makes the life of Apple developers a lot easier and happier.

However, I recently found some annoying problems of KVO while building some reusable programming components ^(I’ll open source as much as possible when ready.)$ for Voodo and future iOS projects.

Observers can not be queried

Observers are stored in dictionaries ^(See NSKeyValueObserving protocol’s observationInfo.)$, so it should be very easy to query whether an object A is a registered observer of object B. But one can’t do that.

Unregistering an unregistered observer throws exception

One can not query whether A is an observer of B in the first place, and can neither try to unregister it from B when one wants to ensure that A is unregistered from B. It is just ridiculous! And why is removing a nonexistent observer so fatal while removing a nonexistent entry from a collection is reasonably ignored? ^(See NSMutableArray’s removeObject: and NSMutableDictionary’s removeObjectForKey:)$

Observers/observees don’t auto-dissolve the KVO relationship in dealloc

It can be easily done in KVO framework code since it already has the data structure keeping the observer-observee relationship information, and is very reasonable things to do – when any part of a relationship is gone the relationship is ended. Without the auto-unregistration, developers’ responsibility is unnecessarily heavier. In fact, it is no easy work in cases where observers outlive observees, because an observee needs to notify its observers of its death so the observers can detach themselves from the dying observee. ^(Normally it is the observers that are doing the KVO relationship management and it is the job of whoever did the connection to do the disconnection, but vice versa)$

All in all

KVO leaves some extra, tedious, and burdensome relationship management work to us while it could be easily and efficiently done at the root of itself. ^(Well, as Appler eskimo1 said in devforums, it is harder than one might think because KVO needs to be both thread safe and GC clean, and must be careful to not impact the performance of code that isn’t using it.)$

The KVO relationship management is especially stressful for observers watching many dynamic observees which is not unusual for generic components – UINavigationController and UITabBarController both manage a dynamic group of UIViewControllers and may observe some properties of them. It is even worse in my component because not only the observee but also the observed properties of them are dynamic. May Apple save me (and you?).


Jul 16 2010

How to Rock and Roll Your Apps

I mean, how to rock and rotate interfaces in your UIKit based apps.

Apple taught me most I need to know about how to manage the interface orientation, but still left some dark corners that I had to explore by myself. Now that I’ve seen the whole landscape, I want to share it with you.

Read the documentation first if you haven’t yet. After that, you should know how to write the rotation code to respond to orientation changes, if only you are notified of the orientation changes in the first place.

Your view controller is always notified of the orientation changes if it is the frontmost view controller – the only view controller, the top modal view controller, the top view controller in the top navigation controller, or the current selected view controller in top tab bar controller. In these cases, simply following the documentation by implementing your rotation logic in those view rotation methods ^(willRotateToInterfaceOrientation:duration:, willAnimateRotationToInterfaceOrientation:duration:, and didRotateFromInterfaceOrientation:)$ is enough.

However, no view rotation message will be sent to your view controller if the rotation occurs when it is not in the frontmost. Well, it is very reasonable behavior though, since its view is invisible then. Laziness is a great virtue here. What’s the point of rotating the invisible view under the hood except for consuming more battery, especially considering that the interface may be rotated back to its original orientation? What makes it a problem is the fact that these messages will neither be sent to your view controller when it becomes the frontmost one later. Your view controller will be never aware of the orientation changes that happen when it is not in the frontmost! One example for better understanding:

  1. A is the current selected view controller in a tab bar controller and the device is in portrait orientation.
  2. View controller B is selected in the tab bar controller.
  3. The device is rotated to landscape orientation.
  4. A is selected again.

See the problem? The orientation is portrait at first, and view controller A presents its view correctly; the orientation becomes landscape later, but A does not know that and still presents a portrait view when it returns to the frontmost.

In fact, the example could be reduced to a simpler one:

  1. B is the current selected view controller in a tab bar controller and the device is in portrait orientation.
  2. The device is rotated to landscape orientation.
  3. View controller A is selected.

The example can be easily extended to view controllers managed by a navigation controller. ^(The situation of modal view controllers is different. The rotation messages will be properly sent to the concerning view controllers. I don’t know why Apple can’t treat them the same way.)$ The problem is reduced to: view controller A initially sets up its view in portrait mode and relies on the code in view rotation methods to adjust the view to new orientations, but view rotation messages are never sent to A so it never rotates its view.

It is clear now that not only view rotation methods should have code for adjusting view for different orientations, but also the initial view setting up code should be orientation dependent. And that’s Apple didn’t tell us.

Finally, here is my way to attack this problem:

May this article help you rotate your apps nicely and may your apps rock.


Jul 15 2010

Documentation Set Generation Tool in Xcode is Wanted

Documentation set generation tool in Xcode to generate documentation sets in the style of Apple Developer Documentation is necessary for a prosperous Apple developer community. The current HeaderDoc and Doxygen are both far from Apple standard.

HeaderDoc is obviously not favored by developers. Doxygen is better and even officially advocated by Apple, but still tedious to use and just can’t generate Apple standard documentations(see a nice example here). Doxyclean is very helpful in converting Doxygen output to resemble Apple Developer Documentation, but seems not capable to generate Xcode Documentation Sets. Following the work of Doxyclean, appledoc supplements some missing features like Xcode Documentation Set generation.

To sum up, there are several third-party tools doing the work that should be better done by Apple in Apple way. Even though they can do their best to generate very Apple like documentations, they can not offer the smooth integration in Xcode that is otherwise possible if it is done by Apple.

So, I’ve posted a bug report(Problem ID: 8193210) to request such a Documentation Set generation tool. If you also want it, please go to duplicate a bug report with following content:

I vote for bug report ‘8193210′.

Summary:
Documentation set generation tool in Xcode to generate documentation set in the style of Apple Developer Documentation is necessary for a prosperous Apple developer community. The current HeaderDoc and doxygen are both far from the Apple standard.

Steps to Reproduce:

Expected Results:

Actual Results:

Regression:

Notes:

Read this article to learn why and how to vote for a bug report. ^(Surely I’ve voted this “international promo codes” bug report since I’m from China.)$