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

Swift中API调用抛出两类错误的原因排查与求助

Swift异步API调用报错解决

遇到的错误

'async' call cannot occur in a global variable initializer

Call can throw, but errors cannot be thrown out of a global variable initializer

问题代码

func getReps() async{
    let apiService = APIService(urlString: (EnvSetup.baseUrl + EnvSetup.apiKey))
    
    await Task{
        let reps: [rep] = try await apiService.getJSON()
        FileManager.endcodeAndSave(objects: reps, fileName: "reps.json")
        print(reps.count)
    }
}

尝试过的调用方式

async{
    await @Published var Reps: [rep] = getReps()
}

使用的APIService代码

import Foundation

public class APIService {
    public let urlString: String
    public init(urlString: String) {
        self.urlString = urlString
    }
    
    public func getJSON<T: Decodable>( dateDecodingStategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
                                       keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys,
                                       completion: @escaping (T) -> Void) {
        guard let url = URL(string: urlString) else {
            fatalError("Error: Invalid URL.")
        }
        let request = URLRequest(url: url)
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            if let error = error {
                fatalError("Error: \(error.localizedDescription)")
            }
            guard let data = data else {
                fatalError("Error: Data is corrupt.")
            }
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = dateDecodingStategy
            decoder.keyDecodingStrategy = keyDecodingStrategy
            
            do {
                let decodedData = try decoder.decode(T.self, from: data)
                completion(decodedData)
            } catch {
                fatalError("Error: \(error.localizedDescription)")
            }
        }.resume()
    }
    
    @available(iOS 14, *)
    public func getJSON<T: Decodable>(dateDecodingStategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,
                                      keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) async throws -> T {
        guard let url = URL(string: urlString) else {
           fatalError("Error: Invalid URL.")
        }
        let request = URLRequest(url: url)
        let (data, response) = try await URLSession.shared.data(for: request)
        guard let _ = response as? HTTPURLResponse else {
            fatalError("Error: Data Request error.")
        }
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = dateDecodingStategy
        decoder.keyDecodingStrategy = keyDecodingStrategy
        guard let decodedData =  try? decoder.decode(T.self, from: data) else {
           fatalError("Error: Decoding error.")
        }
        return decodedData
    }
}

解决方案

1. 修正getReps函数的异步逻辑

原函数里的Task不需要用await包裹,且apiService.getJSON()是抛出错误的方法,必须用do-catch处理错误:

func getReps() async {
    let apiService = APIService(urlString: EnvSetup.baseUrl + EnvSetup.apiKey)
    
    do {
        let reps: [rep] = try await apiService.getJSON()
        FileManager.endcodeAndSave(objects: reps, fileName: "reps.json")
        print(reps.count)
    } catch {
        print("API请求或解码错误:\(error.localizedDescription)")
    }
}

2. 正确调用异步函数

全局变量初始化不支持异步调用和错误抛出,必须在合适的运行时上下文触发异步逻辑,比如视图生命周期、按钮点击事件:

SwiftUI示例:

struct ContentView: View {
    @State private var reps: [rep] = []
    
    var body: some View {
        Text("Reps count: \(reps.count)")
            .onAppear {
                Task {
                    await getReps()
                    // 若需要更新reps,可修改getReps返回数据后赋值
                }
            }
    }
}

带返回值的getReps调用示例:

func getReps() async throws -> [rep] {
    let apiService = APIService(urlString: EnvSetup.baseUrl + EnvSetup.apiKey)
    let reps: [rep] = try await apiService.getJSON()
    FileManager.endcodeAndSave(objects: reps, fileName: "reps.json")
    return reps
}

// 调用处
Task {
    do {
        reps = try await getReps()
    } catch {
        print("错误:\(error)")
    }
}

3. 核心原则

全局环境的初始化是同步执行的,绝对不能包含异步调用或错误抛出逻辑。所有异步操作都要放到函数、方法或Task块中,并在视图生命周期、用户交互等合适的时机触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 03:46:08