Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally Hide Code from the Compiler

So here's the problem. I'm set to release an update soon for iOS that will address some problems in iOS 7. In order to do this, I need to use some specific iOS 7 functions/types. I've made absolutely certain that iOS 7 code will only be executed on iOS 7 and fallback to different code for pre iOS 7. Of course, I'm not allowed to submit with the current Xcode beta, so I'm trying to compile with the current Xcode release. However, I can't seem to find a way to disable this particular warning:

Use of undeclared identifier '<Redacted>'.

Does anyone know of a way to disable this warning using a #pragma. I've tried a bunch of different ones including

-w, -Weverthing, -Wall

but nothing seems to work.

UPDATE Answer: You can't, of course, because the compiler can't compile an identifier it knows nothing about. My solutions was to simply create a #define:

#define <redacted> 1

UPDATE 2 The answer below actually made it much easier. I had already created a #define Xcode5Code(code, alt) that allowed me to execute code blocks conditionally. By modifying it using the solution by @maddy:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
    #define Xcode5Code(code, alt) code
#else
    #define Xcode5Code(code, alt) alt
#endif

This allows me to to easily hide blocks of code from the compiler by using:

Xcode5Code({
    //Code to be execute only with Xcode 5
}, {
    //code to be executed in previous versions of Xcode
})

The main benefit of using the #define Xcode5Code is that Xcode will auto-complete it for you, which is a lot easier than using the full #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000, which Xcode won't auto-complete.

This won't actually distinguish between iOS 7 and pre iOS 7 devices. It only distinguishes what version of iOS the current Xcode can handle. To distinguish between iOS devices versions I use:

NSUInteger DeviceSystemMajorVersion(void) {
    static NSUInteger _deviceSystemMajorVersion = -1;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _deviceSystemMajorVersion = [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] objectAtIndex:0] intValue];
    });
    return _deviceSystemMajorVersion;
}

The above is Apple's code, by the way. To dance around the NDA a little, I'll say that this helps with laying out a root controller's view, because that depends on both the version of Xcode you're using AND the version of iOS that's on the device. And if you're trying to manage beta's as well as production code, this can help a lot. Once you can submit apps with Xcode 5, the #define Xcode5Code will no longer be necessary.

like image 422
Aaron Hayman Avatar asked Aug 23 '13 14:08

Aaron Hayman


1 Answers

If you want to compile your app with two difference versions of Xcode or two different Base SDK settings then you should use compiler directives:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 // iOS 7.0 supported
    // iOS 7 code here
#else
    // Pre-iOS 7 code here
#endif

Do not use this for runtime checks. This solution is only to be used when you must compile your code with two different versions. An example would be you have added iOS 7 code but you still need to compile the code with Xcode 4.6. Using the compile directives allows you to "hide" the iOS 7 code from the compiler using the older Base SDK.

See the "SDK Compatibility Guide" in the docs for more on this and proper runtime checks.

like image 113
rmaddy Avatar answered Oct 23 '22 13:10

rmaddy