seb*_*ien 19 xcode compilation ios touch-id swift
使用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
Run Code Online (Sandbox Code Playgroud)
我正在使用touchID,但我没有使用touchIdLockout ... cste,touchID工作正常.
我该如何删除这些警告?
我将此追踪到一个原因.LAError
从我的代码中的LocalAuthentication框架引用就足以显示这些警告.
重现的步骤(在Xcode 9.2中尝试过):
将这些行添加到AppDelegate.swift
:
import LocalAuthentication
Run Code Online (Sandbox Code Playgroud)
还有一行appDidFinishLaunching
:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let _: LAError? = nil
return true
}
Run Code Online (Sandbox Code Playgroud)构建应用程序.
该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
Run Code Online (Sandbox Code Playgroud)
一个示例项目: 下载示例项目(Xcode 9.2)
作为参考,我向Apple报告了此情况.雷达#36028653.
Mar*_*n R 23
简短回答:它看起来像是一个编译器错误,由导入C枚举导致,该枚举定义了具有相同值的多个常量.
答案很长:不幸的是我没有解决方法如何避免弃用警告,只有可能的解释是什么原因造成的.
该LAError
代码在定义为一个C枚举
<LAError.h>
在LocalAuthentication框架.以下是该定义的摘录:
// 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);
Run Code Online (Sandbox Code Playgroud)
可以看到"旧"(已弃用)和"新"错误代码使用相同的值.例如,既 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 }
// ...
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
这似乎是弃用警告的原因,也是swift-users邮件列表中报告的问题
无法为其编写详尽且无警告的switch语句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,
};
Run Code Online (Sandbox Code Playgroud)
这被导入到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 }
}
Run Code Online (Sandbox Code Playgroud)
第一个(不同的)枚举值有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
Run Code Online (Sandbox Code Playgroud)
此外,无法在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
Run Code Online (Sandbox Code Playgroud)
即使编译器(显然)知道这些情况是详尽的:
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
Run Code Online (Sandbox Code Playgroud)
这对我来说看起来像编译器错误.
是的,这些是随着Apple转向iOS 11和FaceID而出现的新警告.最有可能的是,您正在检查生物识别硬件是否未锁定,是否已注册指纹以及设备是否具有支持硬件.
这里有一个示例设置:
import LocalAuthentication
...
var authContext = LAContext()
var biometricsError: NSError?
authContext?.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &biometricsError)
Run Code Online (Sandbox Code Playgroud)
在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
}
Run Code Online (Sandbox Code Playgroud)
注意: 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
}
Run Code Online (Sandbox Code Playgroud)
这种方法摆脱了Xcode的警告.
如前所述,这是编译器中的错误。Swift团队意识到这一点,您可能想去对该错误进行投票。同时,在其上添加手表,以便在修复后可以删除以下变通办法。
为了不得到警告,您需要做的是:不要提及LAError
。想像LAError
为伏地魔。
而是使用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.")
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3971 次 |
最近记录: |