iOS代码无序执行

时间:2014-07-20 20:29:30

标签: ios concurrency swift

我正在尝试更改标签上的文字,具体取决于TouchID尝试登录的结果,但是会有延迟。当我尝试导航到另一个视图时,会发生同样的事情,例如我的视频显示https://www.youtube.com/watch?v=gQI-93u_B1A

假设我有一个开关来处理不同的登录错误可能性,在每种情况下,如果我尝试更改标签就有这种延迟,如果我使用这些情况来更改字符串变量的内容并尝试分配将此变量的内容添加到函数末尾的标签中,断点显示将变量分配给标签的行在评估登录尝试的块之前执行,这将是代码:

func requestUserAuthentication() {

    var myContext:LAContext = LAContext()
    var authError:NSError?
    var myLocalizedRasonMessage = "Please authenticate using your fingerprint"

    if (myContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error:&authError)) {
        myContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedRasonMessage) { success, error in

            if (success) {
                self.requestAuthenticationOutput = "Login successful"
            }

            else {
                switch error.code {
                case LAError.AuthenticationFailed.toRaw():
                    self.requestAuthenticationOutput = "Login failed"

                case LAError.UserCancel.toRaw():
                    self.requestAuthenticationOutput = "User canceled"

                case LAError.SystemCancel.toRaw():
                    self.requestAuthenticationOutput = "System canceled"

                case LAError.UserFallback.toRaw():
                    self.requestAuthenticationOutput = "User pressed \"Enter Password\""

                default:
                    self.requestAuthenticationOutput = "TouchID is not configured"
                }
            }

        }
    }
    else {
        switch authError!.code {
        case LAError.TouchIDNotAvailable.toRaw():
            self.requestAuthenticationOutput = "No Touch ID on device"
        case LAError.TouchIDNotEnrolled.toRaw():
            self.requestAuthenticationOutput = "No fingers enrolled"
        case LAError.PasscodeNotSet.toRaw():
            self.requestAuthenticationOutput = "No passcode set"
        default:
            self.requestAuthenticationOutput = "Something went wrong getting local auth"
        }
    }

    self.statusLabel.text = self.requestAuthenticationOutput
}

作为输出结果的方式,在案例中立即执行的唯一事情是警报。 我是iOS编程的新手,但我怀疑它与异步代码执行有关,但我还没有完全理解如何使用GCD /队列/等。如何让函数中的最后一行等待第一部分完成执行?任何想法将不胜感激。 (我正在使用swift,但测试ObjC带来了相同的结果)

2 个答案:

答案 0 :(得分:1)

每当你看到像这样的UI发生愚蠢的事情时,你应该考虑一下你调用UI的线程。

阅读evaluatePolicy上的文档:...您将找到这个有用的注释:

  

该方法不会阻止。相反,调用者必须提供一个回复块,以便在评估完成时异步调用。该块在未指定的线程上下文中在框架内部的私有队列上执行。除此之外,无法保证执行块的队列,线程或运行循环。

因为必须在主线程上进行所有UI调用,我想如果你将UI调用发送到主线程(通过dispatch_async()之类的东西),你会看到更好的结果。

答案 1 :(得分:0)

简短的回答是,在指纹验证成功或失败之前,您无法使代码等待(假设设备有能力)。

获得所需效果的一种方法是在成功/错误块中获得结果后更新UI。由于此代码未在Main(UI)线程上执行,因此需要使用GCD在主线程中执行代码。

下面列出的是一个函数updateStatusLabel - 它执行此操作。即使在主线程中执行此操作 - 在API不可用的情况下,它也将非常安全。

func updateStatusLabel()
{
   dispatch_async(dispatch_get_main_queue(), 
      {
        self.statusLabel.text = self.requestAuthenticationOutput
      })
}

var myContext:LAContext = LAContext()
var authError:NSError?
var myLocalizedRasonMessage = "Please authenticate using your fingerprint"

if (myContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error:&authError)) {
    myContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedRasonMessage) { success, error in

        // ...Other code ommitted to set self.requestAuthenticationOutput

        // Update UI
        self.updateStatusLabel()
    }
}
else {
    switch authError!.code {
    case LAError.TouchIDNotAvailable.toRaw():
        self.requestAuthenticationOutput = "No Touch ID on device"
    case LAError.TouchIDNotEnrolled.toRaw():
        self.requestAuthenticationOutput = "No fingers enrolled"
    case LAError.PasscodeNotSet.toRaw():
        self.requestAuthenticationOutput = "No passcode set"
    default:
        self.requestAuthenticationOutput = "Something went wrong getting local auth"
    }
}

  self.updateStatusLabel()
}