Ios 在xcode中设置静态属性时发生EXC_BAD_访问运行时错误

Ios 在xcode中设置静态属性时发生EXC_BAD_访问运行时错误,ios,xcode,swift3,Ios,Xcode,Swift3,正在开发一个物联网程序,但我仍在尝试,该程序现在应该做的只是在用户成功使用触摸ID进行身份验证时显示一条消息。无论程序是首次启动还是在后台激活,每次用户打开程序时都应该显示一条消息。 程序正在运行,但当它到达试图设置跟踪身份验证状态的静态布尔属性的块时,会出现以下错误: 以下是完整的代码: AppDelegate.swift: import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegat

正在开发一个物联网程序,但我仍在尝试,该程序现在应该做的只是在用户成功使用触摸ID进行身份验证时显示一条消息。无论程序是首次启动还是在后台激活,每次用户打开程序时都应该显示一条消息。 程序正在运行,但当它到达试图设置跟踪身份验证状态的静态布尔属性的块时,会出现以下错误:

以下是完整的代码:

AppDelegate.swift:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        print("Launching...")
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        print("Exiting...")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        ViewController.userIsAuthenticated = false
        print("Exited")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        print("Opening...")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        print("Opened")
        let viewInstance = ViewController()
        viewInstance.authenticateUser()
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("Terminating!")
    }


}
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        print("Launching...")
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        print("Exiting...")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        ViewController.userIsAuthenticated = false
        print("Exited")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        print("Opening...")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        print("Opened")
        let viewInstance = ViewController()
        viewInstance.authenticateUser()
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("Terminating!")
    }


}
ViewController.swift:

import UIKit
import LocalAuthentication

@IBDesignable class ViewController: UIViewController {
    //MARK: Properties
    static var userIsAuthenticated: Bool{
        get{
            return false
        }
        set{
            userIsAuthenticated = newValue
            let alert = UIAlertController(title: "", message: "Authentication Successful!", preferredStyle: .actionSheet)
            let viewInstance = ViewController()
            viewInstance.present(alert, animated: true)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.backgroundColor = UIColor.init(red: 0.3, green: 0.48, blue: 0.78, alpha: 1.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func authenticateUser(){
        if ViewController.userIsAuthenticated != true {
            let authenticateUser = LAContext()
            var authenticationError: NSError? = nil
            let authenticationReason = "Authentication is needed to access your house!"
            if authenticateUser.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &authenticationError){
                authenticateUser.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: authenticationReason, reply: {(success, error) in
                    if(success){
                        ViewController.userIsAuthenticated = true
                    }else{
                        print(error!.localizedDescription)
                    }
                })
            }else{
                print("Authentication Error!", authenticationError!)
            }
        }
    }

    func displayAnAlert(title:String?, message: String?) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
            print("Cancel")
        })
        alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
            print("OK")
        })

        self.present(alert, animated: true)
    }

}
import UIKit
import LocalAuthentication

@IBDesignable class ViewController: UIViewController {
    //MARK: Properties
    static var userIsAuthenticated: Bool!{
        didSet{
            let alert = UIAlertController(title: "", message: "Authentication Successful!", preferredStyle: .actionSheet)
            let viewInstance = ViewController()
            viewInstance.present(alert, animated: true)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.backgroundColor = UIColor.init(red: 0.3, green: 0.48, blue: 0.78, alpha: 1.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func authenticateUser(){
        if ViewController.userIsAuthenticated != true {
            let authenticateUser = LAContext()
            var authenticationError: NSError? = nil
            let authenticationReason = "Authentication is needed to access your house!"
            if authenticateUser.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &authenticationError){
                authenticateUser.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: authenticationReason, reply: {(success, error) in
                    if(success){
                        ViewController.userIsAuthenticated = true
                    }else{
                        print(error!.localizedDescription)
                    }
                })
            }else{
                print("Authentication Error!", authenticationError!)
            }
        }
    }

    func displayAnAlert(title:String?, message: String?) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
            print("Cancel")
        })
        alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
            print("OK")
        })

        self.present(alert, animated: true)
    }

}

编辑
现在错误消失了,但警报没有显示,它给了我以下错误:

以下是新代码:

AppDelegate.swift:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        print("Launching...")
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        print("Exiting...")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        ViewController.userIsAuthenticated = false
        print("Exited")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        print("Opening...")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        print("Opened")
        let viewInstance = ViewController()
        viewInstance.authenticateUser()
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("Terminating!")
    }


}
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        print("Launching...")
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        print("Exiting...")
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        ViewController.userIsAuthenticated = false
        print("Exited")
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        print("Opening...")
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        print("Opened")
        let viewInstance = ViewController()
        viewInstance.authenticateUser()
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        print("Terminating!")
    }


}
ViewController.swift:

import UIKit
import LocalAuthentication

@IBDesignable class ViewController: UIViewController {
    //MARK: Properties
    static var userIsAuthenticated: Bool{
        get{
            return false
        }
        set{
            userIsAuthenticated = newValue
            let alert = UIAlertController(title: "", message: "Authentication Successful!", preferredStyle: .actionSheet)
            let viewInstance = ViewController()
            viewInstance.present(alert, animated: true)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.backgroundColor = UIColor.init(red: 0.3, green: 0.48, blue: 0.78, alpha: 1.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func authenticateUser(){
        if ViewController.userIsAuthenticated != true {
            let authenticateUser = LAContext()
            var authenticationError: NSError? = nil
            let authenticationReason = "Authentication is needed to access your house!"
            if authenticateUser.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &authenticationError){
                authenticateUser.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: authenticationReason, reply: {(success, error) in
                    if(success){
                        ViewController.userIsAuthenticated = true
                    }else{
                        print(error!.localizedDescription)
                    }
                })
            }else{
                print("Authentication Error!", authenticationError!)
            }
        }
    }

    func displayAnAlert(title:String?, message: String?) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
            print("Cancel")
        })
        alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
            print("OK")
        })

        self.present(alert, animated: true)
    }

}
import UIKit
import LocalAuthentication

@IBDesignable class ViewController: UIViewController {
    //MARK: Properties
    static var userIsAuthenticated: Bool!{
        didSet{
            let alert = UIAlertController(title: "", message: "Authentication Successful!", preferredStyle: .actionSheet)
            let viewInstance = ViewController()
            viewInstance.present(alert, animated: true)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.backgroundColor = UIColor.init(red: 0.3, green: 0.48, blue: 0.78, alpha: 1.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func authenticateUser(){
        if ViewController.userIsAuthenticated != true {
            let authenticateUser = LAContext()
            var authenticationError: NSError? = nil
            let authenticationReason = "Authentication is needed to access your house!"
            if authenticateUser.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &authenticationError){
                authenticateUser.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: authenticationReason, reply: {(success, error) in
                    if(success){
                        ViewController.userIsAuthenticated = true
                    }else{
                        print(error!.localizedDescription)
                    }
                })
            }else{
                print("Authentication Error!", authenticationError!)
            }
        }
    }

    func displayAnAlert(title:String?, message: String?) {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
            print("Cancel")
        })
        alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
            print("OK")
        })

        self.present(alert, animated: true)
    }

}

由于我对您的问题发表了评论,您编辑了该问题,但出现了一个新错误,表明您试图在不在窗口中的视图上显示警报。这是因为您刚刚创建了一个全新的视图:

let viewInstance = ViewController()
它与任何窗口都不关联。。。因此出现了错误


您可能根本不想要新视图,但可能是您已经拥有的正在执行
authenticateUser()
的视图。如果
userIsAuthenticated
是一个实例属性,那么视图将作为
self
提供,但是您的属性是
static
,因此情况并非如此

如果不为您重新设计解决方案,您的问题就没有简单的答案,这是您需要做的事情!是时候退一步思考了。问问自己,为什么您的属性是静态的,为什么您试图从属性设置器发出警报,等等


HTH

userIsAuthenticated=newValue
导致无限循环。它调用setter,setter调用setter,setter调用删除该行。@vadian但是如果我删除了该行,将如何设置userIsAuthenticated?userIsAuthenticated是一个计算属性(不是存储属性)
userIsAuthenticated
是隐式设置的。您可能会将其与
didSet
观察者混淆。您的
get
for
userIsAuthenticated
始终返回
false
,这可能解释了为什么“它会永远获得身份验证”。您可能对属性在Swift中的工作方式有一些误解,也许是时候回顾一下Swift编程语言中的属性了?嗯