认证服务Completion Handler报错咨询:登录调用自定义认证服务问题
我来帮你排查这个自定义认证服务里Completion Handler的问题,先从你给出的代码片段入手,拆解常见的错误场景和修复方案:
首先,先把你提供的代码片段补全并格式化(方便分析):
func loginWithUserData(userData: Dictionary<String, Any>, completion: @escaping (_ success: DataResponse<Any>) -> Void) { NetworkManager.sharedNetworkManager.performNetworkOperation( url: myEndpoint().userSession(), httpmethod: .post, parameters: userData ) { response in // 你的代码在这里截断了,大概率是问题的核心区域 completion(response) } }
常见错误场景及修复方案
1. 回调参数类型不匹配(编译/运行时直接报错)
如果你的NetworkManager.performNetworkOperation的回调返回类型和completion要求的DataResponse<Any>不一致(比如很多网络库会用Result<DataResponse<Any>, Error>的枚举类型),直接传递会导致编译失败或者运行时崩溃。
修复方案:
先统一回调类型,再传递给completion:
func loginWithUserData(userData: [String: Any], completion: @escaping (DataResponse<Any>) -> Void) { NetworkManager.sharedNetworkManager.performNetworkOperation( url: myEndpoint().userSession(), httpmethod: .post, parameters: userData ) { result in // 假设NetworkManager返回Result枚举类型 switch result { case .success(let response): completion(response) case .failure(let error): // 构造符合要求的失败DataResponse(根据你的DataResponse结构调整) let failedResponse = DataResponse<Any>( request: nil, response: nil, data: nil, result: .failure(error) ) completion(failedResponse) } } }
2. 未处理空响应/无效状态码(隐性逻辑错误)
如果API返回空数据、非2xx状态码,直接把响应传给completion会导致上层逻辑无法正确判断登录结果,误以为是Handler的问题。
修复方案:
在回调里先校验响应有效性:
func loginWithUserData(userData: [String: Any], completion: @escaping (DataResponse<Any>) -> Void) { NetworkManager.sharedNetworkManager.performNetworkOperation( url: myEndpoint().userSession(), httpmethod: .post, parameters: userData ) { response in // 校验HTTP状态码是否合法 if let httpResponse = response.response, !(200...299).contains(httpResponse.statusCode) { let error = NSError(domain: "AuthServiceError", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: "登录请求失败,状态码:\(httpResponse.statusCode)"]) let errorResponse = DataResponse<Any>( request: response.request, response: httpResponse, data: response.data, result: .failure(error) ) completion(errorResponse) return } // 校验响应数据是否为空 guard response.data != nil else { let error = NSError(domain: "AuthServiceError", code: -1, userInfo: [NSLocalizedDescriptionKey: "登录响应数据为空"]) let errorResponse = DataResponse<Any>( request: response.request, response: response.response, data: nil, result: .failure(error) ) completion(errorResponse) return } // 正常传递有效响应 completion(response) } }
3. 循环引用导致的内存泄漏(隐性运行时错误)
因为completion是@escaping闭包,如果在调用loginWithUserData的地方,闭包里直接引用了self而没有用weak/unowned修饰,会导致循环引用,内存无法释放,甚至回调不执行。
修复方案:
调用时使用弱引用:
// 调用示例 AuthService.shared.loginWithUserData(userData: ["username": "yourUsername", "password": "yourPassword"]) { [weak self] response in guard let self = self else { return } // 避免self被释放后的空指针问题 if response.result.isSuccess { self.navigateToHomePage() // 更新UI或执行后续逻辑 } else { self.showLoginError(message: response.result.error?.localizedDescription ?? "登录失败") } }
4. 回调线程错误(UI更新崩溃)
如果NetworkManager的回调在后台线程执行,直接在completion里更新UI会导致崩溃,因为UI操作必须在主线程。
修复方案:
传递completion前切换到主线程:
func loginWithUserData(userData: [String: Any], completion: @escaping (DataResponse<Any>) -> Void) { NetworkManager.sharedNetworkManager.performNetworkOperation( url: myEndpoint().userSession(), httpmethod: .post, parameters: userData ) { response in // 切换到主线程执行completion DispatchQueue.main.async { completion(response) } } }
调试建议
如果以上方案还没解决问题,可以在回调里打印完整的response信息,包括请求URL、参数、响应状态码、数据内容,定位是网络请求问题、API返回问题还是代码逻辑问题:
print("登录请求URL: \(response.request?.url?.absoluteString ?? "未知")") print("响应状态码: \(response.response?.statusCode ?? -1)") print("响应数据: \(String(data: response.data ?? Data(), encoding: .utf8) ?? "空数据")") print("错误信息: \(response.result.error?.localizedDescription ?? "无错误")")
内容的提问来源于stack exchange,提问作者SeaWarrior404

