You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift/SwiftUI POST请求获取JSON类型报错解决方案

问题原因

你遇到的报错翻译为:无法将类型为'(Data?, URLResponse?, Error?) async -> Void'的函数传递给期望同步函数类型的参数。
触发原因很明确:URLSession.shared.dataTask(with: completionHandler:) 方法要求传入的completion回调是同步闭包,但你在闭包内部直接调用了await fetchData()这个异步方法,Swift会自动把当前闭包推断为async异步类型,和方法要求的参数类型不匹配,就会抛出这个错误。

修复方案

你写的getAppConfig本身已经标记为async函数,优先推荐用iOS 15及以上系统原生支持的async/await版本网络请求API,不需要写嵌套回调,逻辑更清晰,也不会出现闭包类型不匹配的问题。

方案1:使用现代async/await语法(推荐,适配iOS 15+)

直接替换整个方法实现即可:

func getAppConfig() async {
    guard let url = URL(string:"https://blasrv.com/appconfig.php") else {
        return
    }
    let body: [String: String] = ["userid": "420", "device": "ios"]
    let finalBody = try? JSONSerialization.data(withJSONObject: body)
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.httpBody = finalBody
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    do {
        // 调用async版本的网络请求方法,无需嵌套回调
        let (data, response) = try await URLSession.shared.data(for: request)
        // 校验响应状态码,避免接口返回错误时仍正常解析
        guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
            print("接口响应异常")
            return
        }
        
        if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
            // 注意:如果接口返回的nickname是字符串而非字符串数组,请将下方类型判断改为 as? String
            if let nickname = json["nickname"] as? String {
                print(nickname)
            }
        }
        
        gotConfig = true
        await fetchData()
    } catch {
        print("请求/解析失败:\(error.localizedDescription)")
    }
}

方案2:兼容低版本iOS的回调写法

如果需要适配iOS 15以下的系统,保留原有dataTask写法即可,只需要把闭包内的异步调用用Task包裹,避免闭包被推断为async类型:

// 只需要修改网络请求回调部分的代码
URLSession.shared.dataTask(with: request) { data, response, error in
    // 优先判断请求错误
    guard error == nil, let data = data else {
        print("请求失败:\(error?.localizedDescription ?? "未知错误")")
        return
    }
    // 校验响应状态码
    guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
        print("响应状态码异常")
        return
    }
    
    do {
        // 原代码中let jsondata = Data(data)是多余操作,回调返回的data本身就是Data类型
        if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
            if let nickname = json["nickname"] as? String {
                print(nickname)
            }
        }
        
        gotConfig = true
        // 用Task包裹异步调用,不改变闭包的同步属性
        Task {
            await fetchData()
        }
    } catch {
        print("数据解析失败:\(error.localizedDescription)")
    }
}
.resume()
额外注意点
  • 你原有代码里let jsondata = Data(data)属于冗余操作,回调返回的data参数本身就是Data类型,不需要二次初始化
  • 网络请求必须先判断error是否为空、响应状态码是否为200,再做数据解析,否则很容易在请求失败时触发解析崩溃
  • 注意核对接口返回字段的类型,绝大多数场景下nickname是字符串类型,你原有代码里as? [String]是转成字符串数组,大概率拿不到返回值,需要根据接口实际返回调整类型判断

内容的提问来源于stack exchange,提问作者user10651308

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 15:36:26