機能 内容
エラーハンドリング 通信失敗 / デコード失敗 を正しく処理する
ステータスコード確認 API が成功か失敗かを確認する
リトライ処理 失敗したらもう一度試す
### エラーの定義
enum APIError: Error {
case invalidURL
case networkError
case serverError(Int) // ステータスコード付き
case decodeError
}
呼び出し
import Foundation
struct WeatherResponse: Codable {
struct CurrentWeather: Codable {
let temperature: Double
let windspeed: Double
}
let current_weather: CurrentWeather
}
class WeatherAPI {
func fetchWeather() async throws -> WeatherResponse {
guard let url = URL(string: "https://api.open-meteo.com/v1/forecast?latitude=35.6895&longitude=139.6917¤t_weather=true") else {
throw APIError.invalidURL
}
let (data, response) = try await URLSession.shared.data(from: url)
// ステータスコードチェック
if let httpResponse = response as? HTTPURLResponse,
!(200..<300).contains(httpResponse.statusCode) {
throw APIError.serverError(httpResponse.statusCode)
}
// JSON デコード
do {
return try JSONDecoder().decode(WeatherResponse.self, from: data)
} catch {
throw APIError.decodeError
}
}
}
func fetchWeatherWithRetry() async {
let api = WeatherAPI()
for attempt in 1...3 {
do {
let result = try await api.fetchWeather()
print("成功: \(result.current_weather.temperature)°C")
return // 成功したら終了
} catch APIError.serverError(let code) {
print("サーバーエラー (\(code)) → リトライ(\(attempt))")
} catch {
print("その他エラー → リトライ(\(attempt))")
}
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待つ
}
print("3回試したが失敗しました 😢")
}
import SwiftUI
struct ContentView: View {
@State private var temperature: String = "__"
var body: some View {
VStack(spacing: 20) {
Text("気温: \(temperature)°C")
.font(.title)
Button("天気を取得(リトライ付き)") {
Task {
await fetchWeatherUI()
}
}
}
.padding()
}
func fetchWeatherUI() async {
let api = WeatherAPI()
for _ in 1...3 {
do {
let result = try await api.fetchWeather()
await MainActor.run {
temperature = String(result.current_weather.temperature)
}
return
} catch {
print("失敗 → 再試行")
try? await Task.sleep(nanoseconds: 800_000_000)
}
}
await MainActor.run {
temperature = "取得失敗"
}
}
}