touchIDLockout在iOS 11.0中已弃用
使用Xcode 9为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中尝试过):
- 创建一个新的iOS应用程序(单一视图模板)。 请注意,iOS部署目标设置为iOS 11.2。
-
将这些行添加到
AppDelegate.swift
:import LocalAuthentication
appDidFinishLaunching
中的appDidFinishLaunching
:func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { let _: LAError? = nil return true }
-
构建应用程序。
let _: LAError? = nil
let _: LAError? = nil
line足以使三个警告出现。 但是,警告与任何特定代码行都没有关联。 它们出现在构建日志中,没有任何文件/行引用:
:0: warning: 'touchIDLockout' was deprecated in iOS 11.0: use LAErrorBiometryLockout :0: warning: 'touchIDNotEnrolled' was deprecated in iOS 11.0: use LAErrorBiometryNotEnrolled :0: warning: 'touchIDNotAvailable' was deprecated in iOS 11.0: use LAErrorBiometryNotAvailable
这是一个截图: Xcode中警告 的屏幕 截图
一个示例项目: 下载示例项目(Xcode 9.2)
作为参考,我向Apple报告了此情况。 雷达#36028653。
简短的回答:它看起来像一个编译器错误,由导入C枚举引起,它定义了具有相同值的多个常量。
答案很长:不幸的是我没有解决方法如何避免弃用警告,只有可能的解释是什么原因造成的。
LAError
代码在LocalAuthentication框架中的
中定义为C枚举。 以下是该定义的摘录:
// 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);
可以看到“旧”(已弃用)和“新”错误代码使用相同的值。 例如, 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邮件列表中报告的问题
- [swift-users]处理库中不推荐使用的枚举案例
为LAError
编写一个详尽且无警告的switch语句是LAError
。
为了certificate我的猜想,我用自定义枚举重现了这个问题:将以下定义添加到macOS 10.13或iOS 11项目的桥接头文件中:
#import 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: // :0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC
此外,无法在switch语句中使用新的枚举值:
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 // :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: // :0: warning: 'C' was deprecated in OS X 10.13: use MyEnumNewC // main.swift:19:9: warning: default will never be executed
这对我来说看起来像编译器错误。
是的,这些是随着Apple转向iOS 11和FaceID而出现的新警告。 最有可能的是,您正在检查生物识别硬件是否未锁定,是否已注册指纹,以及设备是否具有支持硬件。
这里有一个示例设置:
import LocalAuthentication ... var authContext = LAContext() var biometricsError: NSError? authContext?.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &biometricsError)
在iOS 10之前,可以运行如下检查:
if biometricsError?.code == LAError.touchIDNotAvailable.rawValue { // No hardware } if biometricsError?.code == LAError.touchIDNotEnrolled.rawValue { // No fingerprints } if biometricsError?.code == LAError.touchIDLockout.rawValue { // Locked out }
注意: iOS 11引入了上述代码的略微变体。 他们不是对每个错误属性使用LAError.touchID
,而是引入了LAError.biometry
。 因此,您将拥有: biometryNotAvailable
, biometryNotEnrolled
和biometryLockout
。
Apple似乎更喜欢这种方法,而是:
if biometricsError?.code == Int(kLAErrorBiometryNotAvailable) { // No hardware } if biometricsError?.code == Int(kLAErrorBiometryNotEnrolled) { // No fingerprints } if biometricsError?.code == Int(kLAErrorBiometryLockout) { // Locked out }
这种方法摆脱了Xcode的警告。