SwiftUI中在View的onAppear中处理Completion逻辑的求助
解决SwiftUI中JWT验证后切换视图的问题
你的代码主要存在几个关键问题,导致无法正确根据JWT验证结果切换视图,以下是问题分析和修正方案:
核心问题梳理
- 状态变量未使用SwiftUI状态包装器:
validSession是普通变量,修改它不会触发SwiftUI视图重渲染,必须用@State或相关状态包装器标记。 - 异步Completion Handler用法错误:
validateToken是异步方法,没有返回值,你错误地尝试用let接收结果,且Result的判断语法完全错误。 - 后台线程更新UI:URLSession的回调在后台线程执行,直接修改UI状态会导致异常,必须切换到主线程更新。
- 缺少加载状态:验证过程中没有过渡视图,用户会瞬间看到错误的初始视图(LoginView/HomeView)。
修正后的完整代码
LaunchView 修正版
struct LaunchView: View { let keychainManager = KeychainManager() let keychainRecords = KeychainRecords() let tokenManager = TokenManager() // 使用@State包装状态变量,触发视图更新 // nil表示验证中,true/false表示验证结果 @State private var validSession: Bool? = nil var body: some View { ZStack { if let validSession = validSession { // 验证完成,根据结果跳转视图 validSession ? HomeView() : LoginView() } else { // 验证过程中显示加载指示器 ProgressView("验证会话中...") } } .onAppear { validateSession() } } // 抽离验证逻辑,代码更清晰 private func validateSession() { do { let token = try keychainManager.getToken(identifier: keychainRecords.identifier, service: keychainRecords.service) tokenManager.validateToken(token: token) { result in // 切换到主线程更新UI状态 DispatchQueue.main.async { switch result { case .success(let response): // 根据接口返回的消息判断会话有效性 validSession = response.Message == "Success" case .failure(let error): // 任何错误都视为会话无效,跳转到登录页 print("验证失败:\(error)") validSession = false } } } } catch { // 读取Keychain中的Token失败(比如Token不存在) print("读取Token失败:\(error)") validSession = false } } }
TokenManager 优化版(可选)
添加请求头和HTTP状态码校验,避免无效请求:
func validateToken(token: String, completion: @escaping (Result<TokenValidationResponse, NetworkError>) -> Void) { guard let url = URL(string: BASE_URL + TOKEN) else { completion(.failure(.invalidURL)) return } let body = TokenRequestBody(token: token) var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = try? JSONEncoder().encode(body) // 添加Content-Type头,确保服务器正确解析JSON请求体 request.setValue("application/json", forHTTPHeaderField: "Content-Type") URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { completion(.failure(.noData)) return } // 校验HTTP响应状态码,非2xx视为错误 if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) { completion(.failure(.invalidResponse(statusCode: httpResponse.statusCode))) return } guard let tokenValidationResponse = try? JSONDecoder().decode(TokenValidationResponse.self, from: data) else { completion(.failure(.decodingError)) return } print(tokenValidationResponse) completion(.success(tokenValidationResponse)) }.resume() } // 扩展NetworkError,添加无效响应的错误类型 enum NetworkError: Error { case invalidURL case noData case decodingError case invalidResponse(statusCode: Int) }
关键修改说明
- 状态管理:用
@State private var validSession: Bool?标记状态变量,nil表示加载中,验证完成后设置为true/false触发视图更新。 - 异步逻辑处理:在
validateToken的completion闭包里用switch正确处理Result类型,并且通过DispatchQueue.main.async切换到主线程更新UI。 - 错误兜底:任何读取Token失败、网络错误、验证失败的情况,都默认跳转到登录页,保证流程闭环。
- 加载状态:添加
ProgressView作为过渡视图,提升用户体验。
内容的提问来源于stack exchange,提问作者unhep
相关产品推荐
相关产品推荐

