Warning : Love hurts…
November 19th, 2009 by Chris
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
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 isn’t a private API method, but actually a public method on . This leads me to believe that the email from Apple was incorrect in identifying 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 anywhere in our code, but now I am less certain it will guarantee passing the test next time!
(Thanks to Andrew Wooster)

Actually, the key issue with the Three20 library had to do with seriously improper undocumented API usage, to which the author of the library, Joe Hewitt, actually admitted and ultimately removed. Since that time there may be the occasional false positive with regards to this library, but in most cases, these were caused by something completely different.
I probably should have been a little more clear that :
1) The current Three20 library seems to have cleaned up most of the problems. We made similar changes to our own copy of the library before our initial submission, but still ran into the problem described here.
2) The method that was flagged for us was in a category from the Three20 library and as far as I can tell still is in it and the fork I’ve seen referenced as clean from private APIs.
Perhaps the specifics of the binaries submitted cause some apps including Three20 to get flagged for this category and not others.
[...] excellent write-up on the Three20 situation by Rogue Sheep’s Chris [...]
[...] Warning : Love hurts… appstore, we love you but we hate you [...]
To catch some category overrides, run in the Simulator with environment variable OBJCPRINTREPLACED_METHODS=YES.
Is there evidence that the App Store reviewer static analysis tool is different from the one currently in the SDK? IOW, would the current tool in the hands of Snow Leopard-equipped developers have flagged the same issue?
This time without the reformat surprise: OBJC _ PRINT _ REPLACED _ METHODS = YES
Even if you don’t call the method, Apple might be doing so internally and in effect, end up calling your overridden implementation of it. So it’s not completely inert.
this private api check should be part of the app submission and occur BEFORE the app is sent along for manual inspection. devs would know upfront of any offending code saving time for the dev as well as apple. there is no reason for an apple reviewer to perform this task.
Paul :
That is a great observation. I’m not sure if it was indeed the case here, though it certainly could be. The main point I want to make though is that, while this overriding is not something anyone should do, it something you can inadvertently cause to happen without it being obvious.
gparker :
Excellent tip! Thanks for that.
An app I developed for a client was just rejected twice, last week and this week, for use of private API. Both times, it was due to calls from within the Three20 library.
My biggest complaint about it is that all of the offending uses of private API were not flagged in a single email. We resubmitted after the first batch (the UITouch violations), only to get rejected about a week later due to accessing the firstResponder instance variable.
It is clear that although the tool itself may be automated, it isn’t run immediately after submission or we would have received the second rejection much faster.
[...] also links to RogueSheep, whose Postage app has gotten caught via Three20, and has some suggestions to help them help Apple [...]
To be clear, as far as I can tell, there’s no -previousViewController method on UIViewController. The method is on UINavigationController, which is a subclass of UIViewController.
The environment variable Greg Parker mentioned won’t catch this problem. Neither will the clang static analyzer that ships with Snow Leopard.
[...] Incorporated said that their new application, Postage, was rejected by the system because of a false positive. The specifics of the rejection are technical, but in short, RogueSheep used the name of a private [...]
Also, AFAICT, the category method won’t be called for instances of UINavigationController, only for UIViewController. So, if you have an instance of UINavigationController and call -previousViewController, the “official” method on UINavigationController will be called. If you have an instance of UIViewController, the category method will be called.
I have posted about this on the three20 group and the three20 GitHub issue tracker:
http://groups.google.com/group/three20/browse_thread/thread/bcae33d8108ea573 http://github.com/facebook/three20/issues/#issue/105
Hopefully there will be some follow up. Thanks for posting about this.
Matt
[...] Analysis An update to RogueSheep’s Postage app was recently rejected by Apple because of a supposed overriding of a private method in a category. Apple most likely used [...]
Andrew :
Yep that looks right. class-dump doesn’t seem to pick-up a private method named previousViewController. The only one I see is the public UINavigationController method.
So I guess perhaps the analysis tool Apple ran was simply wrong about it being a private API? That makes more sense as well because you would expect a private API method to start with an underscore anyway.
I’m left assuming that this is just a bug in the analysis tool
An application has been rejected because of attribute access of a Core Data call (setPageNumber:), which cannot be found in any framework of Apple but generated from a @dynamic in a Core Data class.
[...] Original source : http://blog.roguesheep.com/2009/11/19/warning-love…; [...]
[...] also links to RogueSheep, whose Postage app has gotten caught via Three20, and has some suggestions to help them help Apple [...]
[...] also links to RogueSheep, whose Postage app has gotten caught via Three20, and has some suggestions to help them help Apple [...]
[...] And you should really do that – some iPhone Apps are rejected currently for using categories that override default code. [...]
[...] also links to RogueSheep, whose Postage app has gotten caught via Three20, and has some suggestions to help them help Apple [...]
[...] also links to RogueSheep, whose Postage app has gotten caught via Three20, and has some suggestions to help them help Apple [...]
[...] tool (the secret static-analyer) which they don’t understand – but trust 100%: Reject apps that haven’t done anything wrong, but which the tool (incorrectly) flags: The notice from Apple indicated that we had used a private method of UIViewController called [...]
[...] That post has been referenced in a number of other articles about App Store rejections by RogueSheep, Daring Fireball, and App Rejections, just to name a few. We’ve had many e-mail conversations [...]
[...] Warning: Love hurts… [...]
[...] Warning: Love hurts… [...]
So why don’t Apple call their method _previousViewController?
leeg :
I think they normally would if it was really a private method. It turns out though, previousViewController is not actually a private method. The error here seems to be in the analysis of the binary incorrectly flagging that as a private.
We just got rejected for use of private API “setThoroughfare:” This is indeed a private API in MKPlaceMark in the MapKit. The thing is that we never call this in our code.
What we do have is an attribute named “thoroughfare” in a Core Data class. setThoroughfare is generated from @dynamic.
Does this imply that all attributes in all core data classes must have names that in no shape or form resembles an attribute found in any of the private API’s?
Oskar :
I think while probably fair intentioned, the tool that is in use right now must not account for a variety of situations that are perfectly legitimate like yours. It seems like the tool is really just doing a very simple check of the binary for strings that are flagged as private. Perhaps its even as simple as running
Perhaps a better approach would be a special build of the OS that is used in the review process. In this special OS build private methods could log when they are called directly from client code. I haven’t really thought about the runtime and if that is really possible or not.
There is a bit of good news though. It seems that the policy has changed so that its not an immediate rejection, at least in some cases to be a warning to change by your next release.
See this article : http://www.macworld.com/article/145044/2009/12/private_apis.html
[...] also links to RogueSheep, whose Postage app has gotten caught via Three20, and has some suggestions to help them help Apple [...]