当使用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中尝试过):
  • 创建一个新的iOS应用(单 View 模板)。请注意,iOS部署目标设置为iOS 11.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"错误代码使用了
    相同的值。例如,LAErrorTouchIDNotAvailableLAErrorBiometryNotAvailable都定义为-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] Handle deprecated enum cases from a library

  • 写出详尽无遗的警告是不可能的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
    

    在我看来,这似乎是一个编译器错误。

    08-16 03:44