使用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中尝试过):
将这些行添加到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)
作为参考,我向Apple报告了此情况。雷达#36028653。
答案 0 :(得分:23)
简短回答:这对我来说看起来像编译错误了 通过导入定义多个常量的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);
人们可以看到&#34; old&#34; (已弃用)和&#34; new&#34;错误代码使用
相同的价值观。例如,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
的语句。
为了证明我的猜想,我用自定义重现了这个问题 枚举:将以下定义添加到桥接头 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
此外,无法在a中使用新的枚举值 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
// <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
这看起来像是一个编译器错误。
答案 1 :(得分:7)
是的,这些是随着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的警告。
答案 2 :(得分:5)
如上所述,这是编译器中的错误。 Swift团队很清楚,您可能想去vote for the bug。同时,在其上添加手表,以便在修复后可以删除以下变通办法。
为了不得到警告,您需要做的是:不要提及LAError
。将LAError
视为Voldemort。
相反,请使用Objective-C样式的错误检查。所有Error
枚举都映射到NSError
,它们是根据域和代码构建的。与它们进行比较的常量也被导出到Swift中。可以在没有警告的情况下命名它们。因此,您的代码可能看起来像这样(希望如此)。
let context = LAContext()
let text = "Authenticate, please!"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: text) { (success, error) in
if success {
print("")
} else {
guard let error = error else {
return print("Should not happen according to the docs!")
}
let nsError = error as NSError
switch nsError.domain {
case kLAErrorDomain:
switch nsError.code {
case Int(kLAErrorUserCancel):
print("User cancelled.")
case Int(kLAErrorBiometryLockout):
print("Biometry lockout.")
default:
print("Unhandled error.")
}
default:
print("Unhandled error domain. Probably will not happen.")
}
}
}
答案 3 :(得分:0)
我为此苦了很长时间。 Oliver的回答使我找到了一个对我有用的解决方案,但以防万一还有其他问题仍然存在-似乎任何对旧LAError值的引用都会产生上面列出的警告。
例如,此简单代码生成警告。删除所有对旧代码的引用,并使用奥利弗的方法。
func evaluateAuthenticationPolicyMessageForLA(errorCode: Int) -> String {
var message = ""
switch errorCode {
case LAError.authenticationFailed.rawValue:
message = "The user failed to provide valid credentials"
default:
message = "Can't use any version of old LAError"
}
return message
}//evaluateAuthenticationPolicyMessageForLA
实际上,它甚至可以更简单。试试这个:
func evaluateAuthenticationPolicyMessageForBiometricsError(biometricsError: Int) -> String {
var message = "I would normally leave this blank"
if biometricsError == kLAErrorBiometryNotAvailable {
message = "Biometrics are not available on this device"
}//if not avail
if biometricsError == kLAErrorBiometryNotEnrolled {
message = "Biometrics are not enrolled on this device"
}//if not enrolled
if biometricsError == kLAErrorBiometryLockout {
message = "Biometrics are locked out on this device"
}//if locked out
return message
}//evaluateAuthenticationPolicyMessageForBiometricsError