Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Easy way to detect if I am using framework not available to older iOS

After a marathon coding session, where I added too much code without keeping track of everything, I now have an app that probably has some iOS 5.0 and 5.1 specific enums, calls and frameworks, however, I want my app to support iOSes back to 4.3.

I was hoping that there was an easy way of setting Xcode to compile as if it were compiling for iOS 4.3, so that I would get errors for all of the offending code that needs to be conditioned out, and/or alternatively coded, for older iOS.

I thought I'd get that by using the compiler option:

-D__IPHONE_OS_VERSION_MAX_ALLOWED=__IPHONE_4_3

but that ends up generating error in system header files, not my code.

Given that most enums and frameworks have their availability included in the header files, I have to think that there is an easy way to do what I need.

Has anyone managed to do such a thing without resorting to downloading older Xcodes with old SDKs? There I may run into the issue of Xcodes that won't function properly under Lion (which is what I am running).

UPDATE: It appears as though I can't install Xcode 3.2.6 on Lion. I now will have to find a Snow Leopard Mac, unless I find a way to use compiler options or forcing Xcode to use old SDKs...

Here is a sample of what @mattjgalloway's answer did for me:

Lumin App Group

/Users/mz/Dev/Working/Lumin/Lumin/MyUIScreen.m

  • 'brightness' is deprecated: TOO NEW!
  • 'brightness' is deprecated: TOO NEW!
  • 'brightness' is deprecated: TOO NEW!
  • 'brightness' is deprecated: TOO NEW!

/Users/mz/Dev/Working/Lumin/Lumin/LuminViewController+Share.m

  • 'TWTweetComposeViewController' is deprecated: TOO NEW!
  • 'TWTweetComposeViewController' is deprecated: TOO NEW!
  • 'TWTweetComposeViewController' is deprecated: TOO NEW!

/Users/mz/Dev/Working/Lumin/Lumin/LuminViewController.m

  • 'scrollView' is deprecated: TOO NEW!
  • 'connectionWithMediaType:' is deprecated: TOO NEW!
  • 'connectionWithMediaType:' is deprecated: TOO NEW!
  • 'AVCaptureDeviceSubjectAreaDidChangeNotification' is deprecated: TOO NEW!
  • 'setSubjectAreaChangeMonitoringEnabled:' is deprecated: TOO NEW!

Very nice.

I placed the following in my project's .pch file, and am planning on doing so for all projects:

#if DEBUG
#define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED __IPHONE_OS_VERSION_MIN_REQUIRED
#import "MJGAvailability.h"
#endif

For any project, I am now automatically watching for SDK issues based on the earliest iOS I am targeting. While there still may be SDK changes I have to worry about, at least I know of most framework additions that are unavailable to an older iOS release.

like image 948
mahboudz Avatar asked Apr 16 '12 10:04

mahboudz


2 Answers

Take a look at my MJGAvailability.h here on GitHub. Basically it defines the right preprocessor #defines so that newer APIs will look like they're deprecated, so you get a compiler warning. There's some documentation at the top of the file, but basically you just do this in your PCH file:

#define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED __IPHONE_4_3
#import "MJGAvailability.h"

For if you want to support down to iOS 4.3.

It's certainly not 100% foolproof, but I find it incredibly useful for doing what you're asking.

If you want to suppress a warning because maybe you know that it's OK to use that API (you've surrounded it with a respondsToSelector for example) then you can do something like this:

UINavigationBar *navBar = self.navigationController.navigationBar;
if ([navBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    [navBar setBackgroundImage:[UIImage imageNamed:@"navbar_bg.png"] forBarMetrics:UIBarMetricsDefault];
#pragma clang diagnostic pop
}
like image 65
mattjgalloway Avatar answered Sep 27 '22 17:09

mattjgalloway


Sorry; completely blew that answer the first time. Let's try this again...

  • Deployment Target sets the lowest OS version you will work with.
  • SDK sets the highest OS version you will work with

Between Deployment Target and SDK, you have to conditionally check for APIs. See the SDK Compatibility Guide for details on that.

You probably just want to use the old SDK instead.

The easiest way to use old SDKs with newer versions is to save a copy of the .sdk directory and copy it into the new version when you upgrade.

You can, however, download the old stuff, too. Apple just hides it. Start in the Downloads for Apple Developers. Find the copy of Xcode you want. Download Xcode 4.1 for Snow Leopard; it includes iOS SDK 4.3. You can install it in parallel with Xcode 4.3, but you don't have to. Mount the disk. Open a terminal (it's just easier that way). Go to /Volumes/Xcode/Packages. You'll find all the SDKs there.

You can try installing it directly, and that may or may not work for you. You can also unpack the .pkg and get the files you want. I typically use a program called The Unarchiver. It can unpack just about anything. That'll give you a directory that includes a file called "Payload". If you double-click that, it'll expand (it's just a tar.gz that they don't include the extension on). That will give you the Platforms directory. Copy that into the Platforms directory in your copy of Xcode and you should be golden.

All that said, I once I've gotten the system working pretty well, I usually switch back to compiling with the latest and using deployment target. It makes it easier to collaborate with others who don't have the old SDK. And Apple may or may not reject due to linking with an old SDK. They've done that in the past; I don't know the current situation there (haven't had it come up in a while). But I'd tend to recommend submitting something built against the latest.

like image 30
Rob Napier Avatar answered Sep 27 '22 17:09

Rob Napier