在初始化之前由闭包捕获的变量'isVericated' - Swift

Posted

技术标签:

【中文标题】在初始化之前由闭包捕获的变量\'isVericated\' - Swift【英文标题】:Variable 'isVericated' captured by a closure before being initialized - Swift在初始化之前由闭包捕获的变量'isVericated' - Swift 【发布时间】:2022-01-15 19:45:52 【问题描述】:

我试图从名为identityVerification 的函数中返回一个名为isVerificated 的布尔变量,因此我可以在tableView 函数中使用它。函数identityVerification通过Face ID或Touch ID启动身份验证,返回变量isVerificated,告知验证是否成功。

换句话说: 我的目标是当你点击 TableView 中的一个单元格时,它应该首先使用 Face ID 或 Touch ID 开始身份验证。然后身份验证成功后,会打开一个新的ViewController。如果身份验证失败,应用会显示一个 AlertController 并显示消息:“Authentication failed”,并且不会打开新的 ViewController。

问题: 当我运行应用程序时出现两个错误:

    (!) 变量“isVericated”在被初始化之前被闭包捕获 (!) 变量“isVericated”在初始化之前使用

代码如下:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        let IDisVarificated = identityVerification()    //here the "identityVerification" function is started
        if IDisVarificated == true 
            if let vc = storyboard?.instantiateViewController(withIdentifier: "detail") as? PasswordTVcontroller 
                navigationController?.pushViewController(vc, animated: true)
            
         else return
    
    
    
    func identityVerification() -> Bool 
        var isVerificated: Bool
        let context = LAContext()
        var error: NSError?

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)    //HERE IS ERROR NUMBER 1
            let reason = "Identify yourself!"

            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) 
                [weak self] success, authenticationError in

                DispatchQueue.main.async 
                    if success 
                        isVerificated = true    //verification was successfull
                     else 
                        let ac = UIAlertController(title: "Authentication failed", message: "You could not be verified; please try again.", preferredStyle: .alert)
                        ac.addAction(UIAlertAction(title: "OK", style: .default))
                        self?.present(ac, animated: true)
                        isVerificated = false     //verification failed
                    
                
            
         else 
            let ac = UIAlertController(title: "Biometry unavailable", message: "Your device is not configured for biometric authentication.", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(ac, animated: true)
            isVerificated = false      //verification failed
        
        
        return isVerificated      //returning a variable with boolean value that tells if verification was successfull or not, HERE IS ERROR NUMBER 2
    

感谢您的帮助!

【问题讨论】:

我认为你可以通过在声明var isVerificated = false上初始化变量来解决问题 isVerificated 声明为初始值为varfalse 将使编译器警告静音,但它不能解决您不会得到异步结果的事实当您从 identityVerification() 函数返回时调用。请参阅我的答案以获得正确的解决方案。 请编辑问题以将其限制为具有足够详细信息的特定问题,以确定适当的答案。 【参考方案1】:

这类问题总是出现在不熟悉异步函数的人身上。

您不能编写一个从LAContext 函数evaluatePolicy(_:localizedReason:reply:) 返回结果的函数。期间。

那个函数是异步的。这意味着它不会返回结果。它立即返回,然后在后台执行您要求它执行的工作。工作完成后,它会调用 reply 闭包。

您的代码尝试在闭包内设置一个局部变量isVerificated。那是行不通的。当闭包运行时,你的函数已经返回了。

您需要重写您的函数 identityVerification 以采用闭包而不是返回函数。重构后的函数可能如下所示:

func identityVerification(completion: (Bool) -> Void) 
        let context = LAContext()
        var error: NSError?

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)    //HERE IS ERROR NUMBER 1
            let reason = "Identify yourself!"

            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) 
                [weak self] success, authenticationError in

                DispatchQueue.main.async 
                    if success 
                        completion(true)
                     else 
                        let ac = UIAlertController(title: "Authentication failed", message: "You could not be verified; please try again.", preferredStyle: .alert)
                        ac.addAction(UIAlertAction(title: "OK", style: .default))
                        self?.present(ac, animated: true)
                        completion(false)
                    
                
            
         else 
            let ac = UIAlertController(title: "Biometry unavailable", message: "Your device is not configured for biometric authentication.", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(ac, animated: true)
            completion(false)
        

【讨论】:

以上是关于在初始化之前由闭包捕获的变量'isVericated' - Swift的主要内容,如果未能解决你的问题,请参考以下文章

在所有成员初始化之前由闭包捕获的 Swift5(+RxSwift) 'self'

C#由变量捕获引起对闭包的思考

'self'由关闭错误捕获&&,||操作者

将不可复制的闭包对象传递给 std::function 参数

由闭包错误自我捕获

闭包中的变量捕获详解