Is there a way for Xcode to warn about new API calls?

10,520

Solution 1

After digging through AvailabilityInternal.h, I realized that all available versions above the Deployment target are tagged with the __AVAILABILITY_INTERNAL_WEAK_IMPORT macro.

Therefore, I can generate warnings by redefining that macro:

#import <Availability.h>
#undef  __AVAILABILITY_INTERNAL_WEAK_IMPORT
#define __AVAILABILITY_INTERNAL_WEAK_IMPORT \
    __attribute__((weak_import,deprecated("API newer than Deployment Target.")))

By placing this code in a project's precompiled header, any use of an API that might cause a crash on the lowest supported iOS version now generates a warning. If you correctly guard the call, you can disable the warning specifically for that call (modified exmaple from Apple's SDK Compatibility Guide):

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    if ([UIPrintInteractionController class]) {
        // Create an instance of the class and use it.
    }
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
    else {
        // Alternate code path to follow when the
        // class is not available.
    }

Solution 2

I've actually released something which helps with testing this sort of thing. It's part of my MJGFoundation set of class called MJGAvailability.h.

The way I've been using it is to apply it in my PCH file like this:

#define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED __IPHONE_4_0
#import "MJGAvailability.h"

// The rest of your prefix header as normal
#import <UIKit/UIKit.h>

Then it'll warn (with perhaps a strange deprecation warning) about APIs which are being used that are too new for the target you set as the "soft max" as per the #define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED. Also if you don't define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED then it defaults to your deployment target.

I find it useful because I can then double check which APIs I'm using that are too new for the deployment target that I've set.

Solution 3

If you use XCode7.3 and above, you can set other warning flag: -Wpartial-availability, then xcode will show warning for API newer than deployment target version enter image description here

Solution 4

On OS X at least, with recent clang/SDK, there is now a -Wpartial-availability option (add it e.g. in "other warning options") One can then define the following macros to encapsulate code that handles runtime testing if the method is supported

#define START_IGNORE_PARTIAL _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wpartial-availability\"")
#define END_IGNORE_PARTIAL _Pragma("clang diagnostic pop")

I haven't test on iOS though.

Solution 5

This is based on Ben S's answer, but incorporates support for GCC and LLVM-GCC. GCC's deprecated attribute doesn't take a message argument like clang's, so passing one produces a compiler error in basically every file.

Place the following code at the top of your ProjectName-Prefix.pch file to get a warning for every use of an API that may not be available in all your targeted versions:

#import <Availability.h>
#undef  __AVAILABILITY_INTERNAL_WEAK_IMPORT
#ifdef __clang__
#define __AVAILABILITY_INTERNAL_WEAK_IMPORT \
__attribute__((weak_import,deprecated("API newer than Deployment Target.")))
#else
#define __AVAILABILITY_INTERNAL_WEAK_IMPORT \
__attribute__((weak_import,deprecated))
#endif

As Ben says, if you're intentionally doing this (perhaps by checking for the selector at runtime), you can hide the warning using this construct:

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    - (void)conditionallyUseSomeAPI {
        // Check for and use the appropriate API for this iOS version
    }
#pragma GCC diagnostic warning "-Wdeprecated-declarations"

Regrettably, you can't do this inside a function, at least in i686-apple-darwin10-llvm-gcc-4.2 (GCC) 4.2.1.

Share:
10,520
Ben S
Author by

Ben S

Mobile Software Engineering Manager at Square currently working on Cash App iOS with a University of Waterloo bachelor's degree in Computer Science, Software Engineering Option. Previous experience at Google, Amazon.com, OpenText, Research In Motion, Sybase and Bridgewater Systems.

Updated on June 05, 2022

Comments

  • Ben S
    Ben S almost 2 years

    On more than one occasion I've seen crashing bugs appear on iOS 3.x due to use of a new call that was introduced in 4.x without proper checking.

    Is there a way for Xcode to warn about classes, methods and procedures that are only available a later version than the deployment target?

    That way I could easily list through all the code and make sure it's properly conditionalized.