XCode有没有办法警告新的API调用?
不止一次,我发现在iOS 3.x上出现了崩溃的错误,因为使用了4.x中引入的新调用,而没有经过适当的检查。
有没有办法让XCode警告只有比部署目标更高版本的类,方法和过程?
这样我可以很容易地列出所有的代码,并确保它的条件化。
我已经发布了一些有助于testing这种事情的东西。 它是我的MJGFoundation类的一部分,名为MJGAvailability.h 。
我一直在使用它的方式是将其应用于我的PCH文件中,如下所示:
#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>
然后它会警告(可能有一个奇怪的弃用警告)关于正在使用的APIs,对于您根据#define __IPHONE_OS_VERSION_SOFT_MAX_REQUIRED
设置为“soft max”的目标来说太新了。 另外,如果您未定义__IPHONE_OS_VERSION_SOFT_MAX_REQUIRED
则默认为您的部署目标。
我觉得这很有用,因为我可以仔细检查我使用的API对于我设置的部署目标来说太新了。
至less在OS X上,使用最近的clang / SDK,现在有一个-Wpartial-availability
选项(例如在“其他警告选项”中添加它)然后可以定义下面的macros来封装处理运行时testing的代码支持的
#define START_IGNORE_PARTIAL _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wpartial-availability\"") #define END_IGNORE_PARTIAL _Pragma("clang diagnostic pop")
我还没有在iOS上testing。
在挖掘AvailabilityInternal.h
,我意识到部署目标之上的所有可用版本都使用__AVAILABILITY_INTERNAL_WEAK_IMPORT
macros标记。
因此,我可以通过重新定义这个macros来产生警告:
#import <Availability.h> #undef __AVAILABILITY_INTERNAL_WEAK_IMPORT #define __AVAILABILITY_INTERNAL_WEAK_IMPORT \ __attribute__((weak_import,deprecated("API newer than Deployment Target.")))
通过将此代码放在项目的预编译头文件中,任何可能导致在受支持的最低版本的iOS版本上崩溃的API的使用现在都会生成警告。 如果您正确地保护了该呼叫,则可以禁用该呼叫的专门警告(修改为Apple的SDK兼容性指南中的示例):
#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. }
如果使用XCode7.3及以上版本,则可以设置其他警告标志: -Wpartial-availability
,则xcode将显示比部署目标版本更新的API的警告
这是基于本S的答案,但是合并了对GCC和LLVM-GCC的支持。 GCC的deprecated
属性不会像clang的那样消息参数 ,所以传递一个基本上每个文件都会产生一个编译器错误。
将以下代码放置在ProjectName-Prefix.pch
文件的顶部,以获取所有目标版本中可能无法使用的API的每个用法的警告:
#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
正如本文所说,如果你有意这样做(也许通过在运行时检查select器),你可以使用这个结构隐藏警告:
#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"
遗憾的是,至less在i686-apple-darwin10-llvm-gcc-4.2 (GCC) 4.2.1
,你不能在函数内部做到这一点。
为了在XCode 5下正常工作,还需要重新定义NS_AVAILABLE和NS_DEPRECATEDmacros,因为CFAvailability.h区分了支持attribute_availability_with_messagefunction的编译器。 复制预编译头文件中“MJGAvailability.h”导入的以下内容,使其与新的Apple LLVM编译器一起工作:
#import <Availability.h> #import <Foundation/NSObjCRuntime.h> #undef CF_AVAILABLE #undef CF_AVAILABLE_MAC #undef CF_AVAILABLE_IOS #undef CF_DEPRECATED #undef CF_DEPRECATED_MAC #undef CF_DEPRECATED_IOS #undef CF_ENUM_AVAILABLE #undef CF_ENUM_AVAILABLE_MAC #undef CF_ENUM_AVAILABLE_IOS #undef CF_ENUM_DEPRECATED #undef CF_ENUM_DEPRECATED_MAC #undef CF_ENUM_DEPRECATED_IOS #undef NS_AVAILABLE #undef NS_AVAILABLE_MAC #undef NS_AVAILABLE_IOS #undef NS_DEPRECATED #undef NS_DEPRECATED_MAC #undef NS_DEPRECATED_IOS #undef NS_ENUM_AVAILABLE #undef NS_ENUM_AVAILABLE_MAC #undef NS_ENUM_AVAILABLE_IOS #undef NS_ENUM_DEPRECATED #undef NS_ENUM_DEPRECATED_MAC #undef NS_ENUM_DEPRECATED_IOS #undef NS_AVAILABLE_IPHONE #undef NS_DEPRECATED_IPHONE #undef NS_CLASS_AVAILABLE #undef NS_CLASS_DEPRECATED #undef NS_CLASS_AVAILABLE_IOS #undef NS_CLASS_AVAILABLE_MAC #undef NS_CLASS_DEPRECATED_MAC #undef NS_CLASS_DEPRECATED_IOS //CF macros redefinition #define CF_AVAILABLE(_mac, _ios) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_##_ios) #define CF_AVAILABLE_MAC(_mac) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_NA) #define CF_AVAILABLE_IOS(_ios) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios) #define CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, ...) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) #define CF_DEPRECATED_MAC(_macIntro, _macDep, ...) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_NA, __IPHONE_NA) #define CF_DEPRECATED_IOS(_iosIntro, _iosDep, ...) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA, __MAC_NA, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) #define CF_ENUM_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios) #define CF_ENUM_AVAILABLE_MAC(_mac) CF_AVAILABLE_MAC(_mac) #define CF_ENUM_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios) #define CF_ENUM_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, ...) CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, __VA_ARGS__) #define CF_ENUM_DEPRECATED_MAC(_macIntro, _macDep, ...) CF_DEPRECATED_MAC(_macIntro, _macDep, __VA_ARGS__) #define CF_ENUM_DEPRECATED_IOS(_iosIntro, _iosDep, ...) CF_DEPRECATED_IOS(_iosIntro, _iosDep, __VA_ARGS__) //NS macros redefinition #define NS_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios) #define NS_AVAILABLE_MAC(_mac) CF_AVAILABLE_MAC(_mac) #define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios) #define NS_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, ...) CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, __VA_ARGS__) #define NS_DEPRECATED_MAC(_macIntro, _macDep, ...) CF_DEPRECATED_MAC(_macIntro, _macDep, __VA_ARGS__) #define NS_DEPRECATED_IOS(_iosIntro, _iosDep, ...) CF_DEPRECATED_IOS(_iosIntro, _iosDep, __VA_ARGS__) #define NS_ENUM_AVAILABLE(_mac, _ios) CF_ENUM_AVAILABLE(_mac, _ios) #define NS_ENUM_AVAILABLE_MAC(_mac) CF_ENUM_AVAILABLE_MAC(_mac) #define NS_ENUM_AVAILABLE_IOS(_ios) CF_ENUM_AVAILABLE_IOS(_ios) #define NS_ENUM_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, ...) CF_ENUM_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep, __VA_ARGS__) #define NS_ENUM_DEPRECATED_MAC(_macIntro, _macDep, ...) CF_ENUM_DEPRECATED_MAC(_macIntro, _macDep, __VA_ARGS__) #define NS_ENUM_DEPRECATED_IOS(_iosIntro, _iosDep, ...) CF_ENUM_DEPRECATED_IOS(_iosIntro, _iosDep, __VA_ARGS__) #define NS_AVAILABLE_IPHONE(_ios) CF_AVAILABLE_IOS(_ios) #define NS_DEPRECATED_IPHONE(_iosIntro, _iosDep) CF_DEPRECATED_IOS(_iosIntro, _iosDep) #define NS_CLASS_AVAILABLE(_mac, _ios) __attribute__((visibility("default"))) NS_AVAILABLE(_mac, _ios) #define NS_CLASS_DEPRECATED(_mac, _macDep, _ios, _iosDep, ...) __attribute__((visibility("default"))) NS_DEPRECATED(_mac, _macDep, _ios, _iosDep, __VA_ARGS__) #define NS_CLASS_AVAILABLE_IOS(_ios) NS_CLASS_AVAILABLE(NA, _ios) #define NS_CLASS_AVAILABLE_MAC(_mac) NS_CLASS_AVAILABLE(_mac, NA) #define NS_CLASS_DEPRECATED_MAC(_macIntro, _macDep, ...) NS_CLASS_DEPRECATED(_macIntro, _macDep, NA, NA, __VA_ARGS__) #define NS_CLASS_DEPRECATED_IOS(_iosIntro, _iosDep, ...) NS_CLASS_DEPRECATED(NA, NA, _iosIntro, _iosDep, __VA_ARGS__)
它没有被集成到工具集中。 testing这个的一个选项就是创build一个运行时检查,这个检查会在开发过程中运行在新版本的os上。
assert([<CLASS> instancesRespondToSelector:@selector(potato)]);
然后将其添加到您的库的初始化例程之一。
你也可以创build一个脚本来计算为特定翻译发出的警告数量 – 如果有问题的警告计数发生变化,那么你有更新。
最新的Xcode没有与其他答案。 这适用于我(只查找UIKit问题)。
原因是较新的叮当声版本具有内置的可用性属性。
#define TESTING_COMPILATION_TARGET // only enable when trying to diagnose what APIs are being inappropriately used #ifdef TESTING_COMPILATION_TARGET #import <Availability.h> #define __MYUNSUPPORTED __attribute((deprecated("API version unsupported"))) #define __MYUNSUPPORTED_IOS_NA __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_2_0 #define __MYUNSUPPORTED_IOS_2_1 #define __MYUNSUPPORTED_IOS_2_2 #define __MYUNSUPPORTED_IOS_3_0 #define __MYUNSUPPORTED_IOS_3_1 #define __MYUNSUPPORTED_IOS_3_2 #define __MYUNSUPPORTED_IOS_4_0 #define __MYUNSUPPORTED_IOS_4_1 #define __MYUNSUPPORTED_IOS_4_2 #define __MYUNSUPPORTED_IOS_4_3 #define __MYUNSUPPORTED_IOS_5_0 #define __MYUNSUPPORTED_IOS_5_1 #define __MYUNSUPPORTED_IOS_6_0 #define __MYUNSUPPORTED_IOS_6_1 #define __MYUNSUPPORTED_IOS_7_0 #define __MYUNSUPPORTED_IOS_7_1 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_8_0 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_8_1 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_8_2 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_8_3 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_8_4 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_9_0 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_9_1 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_9_2 __MYUNSUPPORTED #define __MYUNSUPPORTED_IOS_9_3 __MYUNSUPPORTED #import <Foundation/Foundation.h> #undef CF_AVAILABLE #define CF_AVAILABLE(_mac, _ios) __MYUNSUPPORTED_IOS_##_ios #undef NS_AVAILABLE #define NS_AVAILABLE(_mac, _ios) __MYUNSUPPORTED_IOS_##_ios #undef CF_AVAILABLE_IOS #define CF_AVAILABLE_IOS(_ios) __MYUNSUPPORTED_IOS_##_ios #undef NS_AVAILABLE_IOS #define NS_AVAILABLE_IOS(_ios) __MYUNSUPPORTED_IOS_##_ios #endif // testing #import <UIKit/UIKit.h>
不,没有这样的警告。 但是,当您使用新的API(因为您明显在后面写这些)时,只需检查文档何时可用即可。
另外,如果您支持3.0并使用新SDK进行开发,则必须绝对在运行3.0的实际设备上进行testing
你可以做的另一件事是编写你自己的实用程序来parsing标题中的可用性macros,然后警告你是否调用了你不应该的东西。
不过,我必须重申,如果您定位旧版本并使用较新的SDK,则必须检查文档以查看API何时可用,并进行适当的testing。