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
相关产品推荐
相关产品推荐

