Swift中Face ID调用陷入循环问题求助
问题排查与解决方案
核心问题分析
- 重复验证循环:你注册了
UIApplication.didBecomeActiveNotification,每次应用激活(包括Face ID验证成功后回到应用)都会触发updateView方法,而该方法会无条件调用authenticate(),不管当前是否已经验证通过,导致验证成功后立刻再次触发验证,陷入循环。 - 状态实例不一致:App中使用
@StateObject var dataController = DataController()创建实例,但AppDelegate中调用DataController.shared,若DataController未正确实现单例,会产生两个独立实例,导致isLocked状态无法同步,UI判断和验证逻辑的状态脱节。 - 后台线程更新UI状态:Face ID的回调在后台线程执行,直接修改
@Published属性可能导致UI更新异常。
解决方案步骤
1. 统一DataController实例并修正状态更新
确保DataController实现ObservableObject与正确的单例逻辑,同时在后台线程更新状态时切换到主队列:
import Foundation import CoreData import Combine class DataController: ObservableObject { static let shared = DataController() // 单例实现 @Published var isLocked = false // 默认未验证 // Core Data容器初始化 let container: NSPersistentContainer private init() { container = NSPersistentContainer(name: "YourModelName") container.loadPersistentStores { description, error in if let error = error { fatalError("Core Data加载失败: \(error.localizedDescription)") } } } }
2. 避免重复验证
在authenticate()方法中先检查当前isLocked状态,已验证通过则直接跳过:
func authenticate() { guard !DataController.shared.isLocked else { return } // 已验证则终止流程 let context = LAContext() var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { let reason = "请验证身份以打开应用" context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in DispatchQueue.main.async { // 切换到主队列更新UI状态 if success { DataController.shared.isLocked = true } else { print("验证失败: \(error?.localizedDescription ?? "未知错误")") } } } } else { print("设备不支持生物识别验证") } }
3. 优化应用激活逻辑(可选:SwiftUI原生实现)
如果想摆脱AppDelegate依赖,可直接在App结构体中用onReceive监听激活通知,更贴合SwiftUI架构:
@main struct CollectionApp: App { @StateObject var dataController = DataController.shared let notificationCenter = NotificationCenter.default var body: some Scene { WindowGroup { if dataController.isLocked { ContentView() .environment(\.managedObjectContext, dataController.container.viewContext) } else { Text("未通过身份验证") } } .onReceive(notificationCenter.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in authenticate() } } private func authenticate() { guard !dataController.isLocked else { return } let context = LAContext() var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { let reason = "请验证身份以打开应用" context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in DispatchQueue.main.async { if success { self.dataController.isLocked = true } else { print("验证失败: \(error?.localizedDescription ?? "未知错误")") } } } } else { print("设备不支持生物识别验证") } } }
额外注意事项
- 务必在
Info.plist中添加NSFaceIDUsageDescription键,填写Face ID的使用目的,否则应用会崩溃。 - 若需要应用进入后台后重新锁定(切换到其他应用再返回需重新验证),可监听
UIApplication.willResignActiveNotification,触发时设置isLocked = false。
内容的提问来源于stack exchange,提问作者multiverse
相关产品推荐
相关产品推荐

