当使用Xcode 9 for IOS11编译我的应用程序时,出现以下警告:
warning: 'touchIDLockout' was deprecated in iOS 11.0: use LAErrorBiometryLockout
warning: 'touchIDNotEnrolled' was deprecated in iOS 11.0: use LAErrorBiometryNotEnrolled
warning: 'touchIDNotAvailable' was deprecated in iOS 11.0: use LAErrorBiometryNotAvailable
我正在使用touchID,但未使用touchIdLockout ... cste,而touchID正常工作。
如何删除这些警告?
编辑(不是原始作者):
我将其归结为一个原因。在我的代码中引用LocalAuthentication框架中的
LAError
足以使这些警告出现。重现步骤(在Xcode 9.2中尝试过):
AppDelegate.swift
中:import LocalAuthentication
和
appDidFinishLaunching
中的一行:func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let _: LAError? = nil
return true
}
let _: LAError? = nil
行足以使三个警告出现。但是,警告与任何特定的代码行都没有关联。它们出现在构建日志中,没有任何文件/行引用:<unknown>:0: warning: 'touchIDLockout' was deprecated in iOS 11.0: use LAErrorBiometryLockout
<unknown>:0: warning: 'touchIDNotEnrolled' was deprecated in iOS 11.0: use LAErrorBiometryNotEnrolled
<unknown>:0: warning: 'touchIDNotAvailable' was deprecated in iOS 11.0: use LAErrorBiometryNotAvailable
这是屏幕截图: Screenshot of the warnings in Xcode
和一个示例项目: Sample project for download (Xcode 9.2)
作为引用,我向苹果公司报告了此事。雷达#36028653
最佳答案
简短答案:对我来说,这似乎是编译器错误,是由
通过导入定义多个常量的C枚举
具有相同的值。
详细答案:不幸的是,我没有解决方法来避免过时
警告,只有可能的解释是什么原因引起的。LAError
代码定义为C中的枚举
LocalAuthentication框架中的<LAError.h>
。这是一个
该定义的摘录:
// Error codes
#define kLAErrorAuthenticationFailed -1
#define kLAErrorUserCancel -2
// ...
#define kLAErrorTouchIDNotAvailable -6
#define kLAErrorTouchIDNotEnrolled -7
#define kLAErrorTouchIDLockout -8
// ...
#define kLAErrorBiometryNotAvailable kLAErrorTouchIDNotAvailable
#define kLAErrorBiometryNotEnrolled kLAErrorTouchIDNotEnrolled
#define kLAErrorBiometryLockout kLAErrorTouchIDLockout
typedef NS_ENUM(NSInteger, LAError)
{
LAErrorAuthenticationFailed = kLAErrorAuthenticationFailed,
LAErrorUserCancel = kLAErrorUserCancel,
// ...
LAErrorTouchIDNotAvailable NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotAvailable") = kLAErrorTouchIDNotAvailable,
LAErrorTouchIDNotEnrolled NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotEnrolled") = kLAErrorTouchIDNotEnrolled,
LAErrorTouchIDLockout NS_ENUM_DEPRECATED(10_11, 10_13, 9_0, 11_0, "use LAErrorBiometryLockout")
__WATCHOS_DEPRECATED(3.0, 4.0, "use LAErrorBiometryLockout") __TVOS_DEPRECATED(10.0, 11.0, "use LAErrorBiometryLockout") = kLAErrorTouchIDLockout,
// ...
LAErrorBiometryNotAvailable NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotAvailable,
LAErrorBiometryNotEnrolled NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotEnrolled,
LAErrorBiometryLockout NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryLockout,
// ...
} NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);
可以看到“旧”(已弃用)和"new"错误代码使用了
相同的值。例如,
LAErrorTouchIDNotAvailable
和LAErrorBiometryNotAvailable
都定义为-6
。这在C语言中完全有效,但是Swift
enum
的原始值必须彼此不同。显然,Swift导入器通过以下方式解决了该问题
将新案例/重复案例映射到静态变量。
这是Swift映射的摘录:
public struct LAError {
public init(_nsError: NSError)
public static var _nsErrorDomain: String { get }
public enum Code : Int {
case authenticationFailed
case userCancel
// ...
@available(iOS, introduced: 8.0, deprecated: 11.0, message: "use LAErrorBiometryNotAvailable")
case touchIDNotAvailable
@available(iOS, introduced: 8.0, deprecated: 11.0, message: "use LAErrorBiometryNotEnrolled")
case touchIDNotEnrolled
@available(iOS, introduced: 9.0, deprecated: 11.0, message: "use LAErrorBiometryLockout")
case touchIDLockout
// ...
@available(iOS 11.0, *)
public static var biometryNotAvailable: LAError.Code { get }
@available(iOS 11.0, *)
public static var biometryNotEnrolled: LAError.Code { get }
@available(iOS 11.0, *)
public static var biometryLockout: LAError.Code { get }
// ...
}
// ...
}
这似乎是导致弃用警告的原因,并且
也针对swift-users邮件列表中报告的问题
写出详尽无遗的警告是不可能的
LAError
的switch语句。为了证明我的猜想,我用习俗重现了这个问题
枚举:在桥接头中添加以下定义
macOS 10.13或iOS 11项目的文件:
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, MyEnum)
{
MyEnumA = 1,
MyEnumB = 2,
MyEnumC NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use MyEnumNewC") = 3,
MyEnumNewC NS_ENUM_AVAILABLE(10_13, 11_0) = 3,
};
这是作为导入到Swift
public enum MyEnum : Int {
case A
case B
@available(OSX, introduced: 10_10, deprecated: 10_13, message: "use MyEnumNewC")
case C
@available(OSX 10_13, *)
public static var newC: MyEnum { get }
}
对于第一个(不同的)枚举值有3种情况,而静态
重复值的属性。
实际上,对
MyEnum
的任何使用都会触发弃用警告:// main.swift:
print(MyEnum.A) // Or: let _: MyEnum? = nil
// Build log:
// <unknown>:0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC
此外,无法在
切换语句:
func foo(err: MyEnum) {
switch err {
case .A:
print("A")
case .B:
print("B")
case .newC:
print("C")
}
}
// Build log:
// main.swift:12:9: error: switch must be exhaustive
// <unknown>:0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC
即使编译器(显然)知道这些情况都是详尽的:
func foo(err: MyEnum) {
switch err { // Switch must be exhaustive
case .A:
print("A")
case .B:
print("B")
case .newC:
print("C")
default:
print("default")
}
}
// Build log:
// <unknown>:0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC
// main.swift:19:9: warning: default will never be executed
在我看来,这似乎是一个编译器错误。