Wanna be 3.x compatible? Not so simple!
So we got the new shiny iOS 4 with the new not-so-shiny SDK 4. Most desirable aspect of using SDK 4 and iOS 4 functions is to be backward compatible with iPhone OS 3.x. This is where you should set your iPhone OS Deployment Target to iPhone OS 3.0 or anything else you want to be compatible with.
![]()
This is the official method, and since SDK 4 does NOT come with 3.x headers, the only method to make your app run on 3.x. But it is not so simple, because now in your Xcode you are using iOS 4 API. So how do you know you are not using classes or methods that do not exist in 3.x and putting them into your code will crash your app on 3.x device? You don’t!
Unfortunately Xcode will warn you about deprecated API, but will NOT warn you about API that does not exist on your deployment target. I buy you a beer if you can find such warning option in Xcode project configuration.
This would be acceptable if you could test your application on iPhone 3.x OS Simulator, but there is no any in SDK 4 (neither as an option), hence you can’t absolutely tell your app won’t gonna blow on iPhone OS 3.x if you upgraded your TESTING devices to iOS 4.
I have spent a while trying to figure our what was Apple’s engineers official statement about that on devforums. And they say if you want to test 3.x compatibility you need get a device with iPhone OS 3.x. Huh? So I shall buy an new iPhone expecting it won’t have iOS 4 on board, because there is no (legal) way to downgrade existing device to 3.x.
Trying to find out a more reasonable way I have ended up with installing an OLD SDK 3.2 on /Developer-3.2. Finally tested my application… but fiddling with SDK 4 was not over. (NOTE: Obviously this method isn’t really free as you gonna lost 4GB for old SDK installation and 2.5GB for download, but it far less expensive than getting a new old 3.x device.)
Still there are few gotchas with this method
And here is one of them. If you happen to use iOS4 API in your code, Apple says that your shall check functions (and class) pointers against nil.
One of the new classes introduced by iOS4 API is UITapGestureRecognizer. I happened to know that because 3.x SDK complained about unknown UITapGestureRecognizer class. So I tried in my code:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizerClass alloc]
initWithTarget:self action:@selector(handleSingleTap:)];
if( singleTap != nil ) {
// do something, we shall be there only on iOS4
Should be enough to be compatible with 3.x device compiling on SDK 4, since UITapGestureRecognizer is introduced by iOS4 API I expected that on 3.x it will be nil so singleTap will be nil too! (BTW. It won’t compile with SDK 3.x I have just installed ;P)
I have sent my app to beta tester with 3.x device, that replied the app is still crashing. So my reasoning about nil was NOT true. Okay, fine, let’s try with:
Class TapGestureRecognizerClass = NSClassFromString(@"UITapGestureRecognizer");
if( TapGestureRecognizerClass != nil ) {
// do something, we shall be there only on iOS4
Again crashes on 3.x device.
I have lost one day on communication with beta tester and scratching my head. You know why? Because UITapGestureRecognizer actually do EXIST in iPhone OS 3.x but it is NOT in the public API. Moreover it misses some methods that do exist in iOS 4 API, so finally I ended up with something like this:
Class TapGestureRecognizerClass = NSClassFromString(@"UITapGestureRecognizer");
if( TapGestureRecognizerClass != nil ) {
UITapGestureRecognizer *singleTap = [[TapGestureRecognizerClass alloc] initWithTarget:self action:@selector(handleSingleTap:)];
if( singleTap != nil ) {
if( [singleTap respondsToSelector:@selector(setNumberOfTapsRequired:)] ) {
[singleTap setNumberOfTapsRequired:1];
}
// .. and checking other selectors
And this was my WORKING method to be compatible with 3.x and using some of iOS 4 API. Crazy enough?


And now you just have to hope that this will not trigger “using undocumented features” during app submission?
Yeah, something like that, but UITapGestureRecognizer isn’t actually undocumented feature because it is right there in iOS 4 API docs, the trick is that it does exist in 3.0-3.1.3 OS too while it shouldn’t as documentation states “Available in iPhone OS 3.2 and later.” So one may wonder what does actually “available” means in this context? “Available to you – you can use it”, or just “does exist”.
I would really like to know the answer to that last question, Adam. UITapGestureRecognizer really does exist in 3.0 – 3.1.3, can we use it?
Will it flag a rejection from Apple when we submit to the App Store?
Will it even work on a 3.0 device?
Now that Apple is requiring us to drop support for 2.x and set 3.x as our minimum target, it would be really nice to know if we could use Gesture Recognizers across the board.
I’ll keep monitoring this blog post. Hopefully someone will find the answer and post here…
Bryan: I’ll give you an answer ASAP my next app will pass through AppStore validation process. I hope this should no longer than end of this week.
I am going to bet that it is OK to use. I would be more worried about the quality but even that I am not so worried because Apple is probably using it.
Thanks for the post, you saved me the trouble of implementing my own UITapGestureRecognizer for an obsolete os! If I keep my gesture needs minimal, this should work until 4.0 is prevalent.
I was put off by the fact that setDelegate on the recognizer was not available, but that is really only for more advanced gesture recognition. The target is all that I need for my app.
I do also hate this Apple way of crapping on developers. XCode itself is not that great, but I get by with it. But this “oh, we won’t support all older SDKs” and “we won’t give any warnings depending on the targets” etc stuff is horrible. Not to mention the ObjC way of using selectors that are checked runtime. Argh. Wonder how much power goes to just finding the methods runtime etc compared to C/C++ way of doing things. Not to mention it’s always better to get errors during compilation (oh, sure, “object might not respond to X” is there, but still…)
I’m also interested in seeing what they’ll say about this “undocumented feature usage” since it should not be allowed, but since it’s there… With compile time resolving even this wouldn’t be a problem
Bryan: The application has passed validation and is now in AppStore.
Symbiatch: I do agree that “oh, we won’t support all older SDKs” and “we won’t give any warnings depending on the targets” together with iPhone OS Deployment Target makes kind of schizophrenia. On one hand Deployment target is pretty neat way to keep things simple and not clutter your HDD with old SDK libraries, but on the other there’s no way to test program with older simulators (where single OS simulator image is ~100MB) and absolutely no warnings even IT IS POSSIBLE to make such warnings as every API in headers (.h) has a mark for what version it is available (and optionally when it was depreciated). So we got a pretty solid hammer, so what it has no handle ;P !?
That’s encouraging news Adam.
I guess I overlooked this question initially, but you may have gotten past the review board at Apple, but what are you doing for the actual functionality on iOS 3? I’m guessing those Single and Double taps you’re using the Gesture Recognizer for are pretty important. You may have found a way around XCode errors, but what does someone with an old iPhone get? Limited functionality?
Adam:
It is good to hear the app made it through app store review.
Symbiatch:
The C++ is the best way to having a product late or never completed, a very non bureaucratic and complex language for not much benefit. One can’t really argue that in general a C++ program crashes less than Objective C. In fact, I have found the opposite despite C++’s supposed superior type safety. Objective C far more flexible and productive, even if the syntax is very odd and may use a couple extra cycles for this flexibility. There may be other languages coming that are better, but I think it may have the right balance of type safety, performance and dynamicism. I mention performance because it is compiled unlike Perl, Python or Ruby. I am not saying C++ should never be used almost every language has its place, but I bet there are better options out there.
Since I am totally new to iPhone Development I ran into the same problem. So thanx for the hint. However, I do not know how to access the private API and/or get gestures working on iOS3.1. Can you please give an example or send me a mail?
“And they say if you want to test 3.x compatibility you
need get a device with iPhone OS 3.x. Huh? So I shall buy an new
iPhone expecting it won’t have iOS 4 on board, because there is no
(legal) way to downgrade existing device to 3.x.” Something I doubt
…
@chalremo – Testing is the hardest part of all Application development. Always has been. Always will be.
If you develop web sites, you need to test your site on IE6, IE7, IE8, Firefox, Chrome, Safari and Opera (Windows), and Safari, Firefox, Chrome (Mac) at minimum.
If you develop desktop apps you need to test on Win XP, Win Vista & Win 7 and/or Leopard & Snow Leopard at minimum.
None of that is “easy”, which is why most lazy developers skip the testing and just make sure it works on their machine. Hence all the crappy software and web sites you see every day.
The iPhone is no different. To do it “right”, you have to test on different devices and iOS levels. iPod Touch, iPhone, iPad / iOS 3, iOS 3.2, iOS 4, iOS 4.2. If you don’t have all of those — and most of us don’t — you ask around to friends and family to get access to as much as you can, then test the rest in the simulator.