如何在简易终端应用中等待LAContext.evaluatePolicy的执行结果
解决方案
你可以用GCD的DispatchSemaphore实现阻塞等待,这个API从macOS 10.10开始就支持,完全适配你当前的系统版本,不需要用到macOS 12+的并发特性。
实现逻辑
- 在调用
evaluatePolicy之前初始化一个计数为0的信号量 - 在
evaluatePolicy的回调末尾,无论验证成功还是失败,都给信号量发送+1信号 - 在你标注需要阻塞的位置调用信号量的等待方法,阻塞当前线程直到收到信号
修改后的完整代码
import LocalAuthentication @_cdecl("authenticate") public func authenticateUser() { let context = LAContext() context.localizedFallbackTitle = "Please use your password" context.localizedCancelTitle = "Abort" var authorizationError: NSError? let permissions = context.canEvaluatePolicy( LAPolicy.deviceOwnerAuthentication, // TouchId or passcode error: &authorizationError ) if permissions { let biometry = context.biometryType if (biometry != LABiometryType.touchID) { print("TouchID not available") return } let reason = "Identify yourself!" print(reason) // 初始化信号量,初始计数为0 let sema = DispatchSemaphore(value: 0) context.evaluatePolicy( LAPolicy.deviceOwnerAuthentication, localizedReason: reason ) { (success: Bool, error: Error?) -> Void in defer { // 回调执行完毕后发送信号,解除主线程阻塞 sema.signal() } if success { print(" You may enter") } else { print(" Authentication failed") print(error?.localizedDescription ?? "Failed to authenticate") } } // 阻塞当前线程,直到收到信号 sema.wait() } else { let ac = "Touch ID not available, Or Your device is not configured for Touch ID." print(ac) } } authenticateUser()
额外说明
- 这个实现是同步阻塞的,
authenticateUser方法会等到TouchID验证完成后才会返回,刚好适配你C语言调用的场景 - 不需要开启主队列Runloop,也不需要用到高版本的async/await特性,在你当前的macOS 11.6 + Swift 5.5环境下可以直接编译运行
- 编译命令和你之前的保持一致即可:
swiftc main.swift ./main
内容的提问来源于stack exchange,提问作者bric3
相关产品推荐
相关产品推荐

