如何改写Alamofire POST请求函数以返回响应字典?
如何改写Alamofire POST请求函数以实现复用并返回响应结果
你的需求非常典型——我们需要把网络请求逻辑封装成可复用的模块,同时解决异步请求无法直接返回结果的问题。原代码的核心问题在于把UI逻辑(MBProgressHUD)和网络请求耦合在一起,而且没有提供获取请求结果的有效途径。下面是具体的改造方案:
核心思路:用Completion Handler传递异步结果
因为网络请求是异步操作,无法通过函数返回值直接拿到结果,所以我们需要用**闭包(Completion Handler)**来传递成功/失败的回调。同时,为了让函数更通用,应该把UI相关的逻辑从请求函数中剥离,让调用者根据自身场景处理UI。
改写后的代码
1. 定义通用的API请求函数
import Alamofire // 自定义枚举,清晰区分成功/失败的结果类型 enum APIResult { case success([String: Any]) case failure(Error) } func callAPI(url: String, params: [String: Any], completion: @escaping (APIResult) -> Void) { // 可添加全局通用请求头,比如Token、Content-Type等 let headers: HTTPHeaders? = [ "Content-Type": "application/json" // "Authorization": "Bearer \(yourAuthToken)" ] Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers) .responseJSON { response in switch response.result { case .success(let value): // 尝试解析为字典,解析失败则返回自定义错误 if let resultJson = value as? [String: Any] { completion(.success(resultJson)) } else { let parseError = NSError(domain: "APIParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "响应格式不是预期的字典类型"]) completion(.failure(parseError)) } case .failure(let error): completion(.failure(error)) } } }
2. 调用示例(在ViewController中)
// 显示HUD(UI逻辑放在调用方,让请求函数更通用) let hud = MBProgressHUD.showAdded(to: self.view, animated: true) hud.contentColor = .red // 准备请求参数和URL let targetURL = "https://your-api-domain.com/your-endpoint" let requestParams = ["username": "testUser", "password": "123456"] // 调用API callAPI(url: targetURL, params: requestParams) { result in // 回到主线程处理UI操作 DispatchQueue.main.async { hud.hide(animated: true) switch result { case .success(let resultJson): print("请求成功:\(resultJson)") // 在这里处理成功逻辑,比如更新UI、跳转页面等 case .failure(let error): print("请求失败:\(error.localizedDescription)") // 处理错误,比如弹出提示框告知用户 } } }
优化点说明
- 分离UI与网络逻辑:把HUD的显示/隐藏放到调用方,让请求函数只专注于网络操作,这样在不需要HUD的场景(比如后台静默请求)也能复用该函数。
- 自定义
APIResult枚举:让回调结果更清晰,调用方可以通过switch语句轻松处理成功和失败的分支。 - 完善错误处理:如果服务器返回的JSON不是预期的字典格式,我们手动创建错误返回给调用方,避免崩溃或静默失败。
- 全局请求头配置:可以在函数中统一配置通用请求头,避免每个调用都重复设置。
进一步封装(可选)
如果你的项目有大量API请求,可以把这个函数封装到单例类中,方便管理全局配置(比如baseURL、超时时间、请求拦截器等):
class APIManager { static let shared = APIManager() private let baseURL = "https://your-api-domain.com" // 私有化构造函数,确保单例模式 private init() {} func callAPI(endpoint: String, params: [String: Any], completion: @escaping (APIResult) -> Void) { let fullURL = baseURL + endpoint // 可添加超时时间、会话配置等全局设置 let sessionManager = Session.default sessionManager.request(fullURL, method: .post, parameters: params, encoding: JSONEncoding.default) .responseJSON { response in // 同上述请求处理逻辑 switch response.result { case .success(let value): if let resultJson = value as? [String: Any] { completion(.success(resultJson)) } else { let parseError = NSError(domain: "APIParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "响应格式不是预期的字典类型"]) completion(.failure(parseError)) } case .failure(let error): completion(.failure(error)) } } } } // 调用示例 APIManager.shared.callAPI(endpoint: "/login", params: ["username": "test", "password": "123"]) { result in // 处理请求结果 }
这样你的API请求逻辑就完全解耦,并且可以在整个项目中高效复用了。
内容的提问来源于stack exchange,提问作者Vinu Jacob
相关产品推荐
相关产品推荐

