Warning : Love hurts…

Sometimes the ones you love reject you. If you are an iPhone developer this is probably a concept with which you are already intimately familiar. We love developing for the iPhone, but sometimes the App Store and its app review process leaves us feeling a little dejected.

One of our applications was just rejected about halfway through the review process and it seemed like a unique enough situation that it was worth sharing as a warning to our comrades in the trenches.

Over the past couple of weeks, there have been several reports of iPhone Apps being rejected for use of private APIs. Many of the rejections are from developers that have used the extremely popular Three20 library from ex-iPhone developer Joe Hewitt. The developing consensus is that recently Apple has started using a static code analyzer to flag applications that have used private API calls.

We use a bit of the code from the Three20 library in Postage and caught wind of the issues people had while getting through the review process right before we submitted a new edition of Postage and a couple of related updates. We discovered that even though we didn’t explicitly use the offending code from the library, it was still being linked into our executable because it was in an Objective-C category that added functionality to existing classes. We quickly removed the private API calls from our copy of the library and submitted our new application and updates to Apple.

Nonetheless, we found out earlier this week that our new application was rejected for private API use. The notice from Apple indicated that we had used a private method of

UIViewController

called

previousViewController

. Interestingly enough, we did not explicitly use this call anywhere in our code. Looking a bit into the version of the Three20 library we were using revealed that it coincidentally contained a category that added a method to

UIViewController

called

previousViewController

.

Once again none of our code or the portions of the Three20 library we used actually exercised this method, but it would appear that the act of compiling and statically linking brings in all the category methods contained in the included headers. I believe that in this case, the category method overrides the built in method, so I’m left with the impression that even if we had been exercising the method in question it would have not been actually using the private API.

While this namespace collision problem is often a topic of debate and pain already among Cocoa developers, those of us developing on the iPhone apparently need to take some extra care now because simply choosing the name of a private API method for your own category method name could result in App Store rejection. Even if you are careful to prefix your own category methods, be sure to take extra caution when incorporating foreign code into your project.

Hopefully this and other possible false positive problems with the new code analysis portion of App Store submissions will be addressed soon. Personally, I’d love to see Apple give us access to the analysis tool to run against our own builds before submission. Or if that’s not possible, perhaps a modification to the review process so this automated analysis happens sooner in the process so we don’t lose so much ground in the now 14-day wait for the review process to complete.

UPDATE :

After looking at a class-dump of the 3.0 frameworks It looks like

previousViewController

isn’t a private API method, but actually a public method on

UINavigationController

. This leads me to believe that the email from Apple was incorrect in identifying

previousViewController

as private. Perhaps the analyzer is tripped-up by a category and a subclass defining the same method? If it is just a bug in the analyzer I guess we can’t really nail down any specific cause of the problem at this time. We made sure there was no trace of any method called

previousViewController

anywhere in our code, but now I am less certain it will guarantee passing the test next time!

(Thanks to Andrew Wooster)