非同期で呼び出す仕組み
import SwiftUI
struct ContentView: View {
@State private var temperature: String = "__"
@State private var windspeed: String = "__"
@State private var showSheet = false
var body: some View {
VStack(spacing: 20) {
Text("東京の現在天気")
.font(.title)
Text("気温: \(temperature)°C")
Text("風速: \(windspeed)m/s")
Button("天気を取得") {
Task {
await fetchWeather()
}
}
Button("詳細を表示(ボトムシート)") {
showSheet = true
}
}
.padding()
.sheet(isPresented: $showSheet) {
BottomSheetView(
temperature: temperature,
windspeed: windspeed
)
.presentationDetents([.fraction(0.3), .medium, .large])
.presentationDragIndicator(.visible)
}
}
func fetchWeather() async {
guard let url = URL(string: "https://api.open-meteo.com/v1/forecast?latitude=35.6895&longitude=139.6917¤t_weather=true") else { return }
do {
// 非同期で通信(完了を待つ)
let (data, _) = try await URLSession.shared.data(from: url)
let decoded = try JSONDecoder().decode(WeatherResponse.self, from: data)
// メインスレッドでUI更新
await MainActor.run {
self.temperature = String(decoded.current_weather.temperature)
self.windspeed = String(decoded.current_weather.windspeed)
}
} catch {
print("エラー: \(error.localizedDescription)")
}
}
}
struct BottomSheetView: View {
let temperature: String
let windspeed: String
var body: some View {
VStack(spacing: 16) {
Text("詳細情報")
.font(.title3)
.bold()
Text("気温: \(temperature)°C")
Text("風速: \(windspeed)m/s")
Text("データ提供: open-meteo.com")
.font(.footnote)
.foregroundColor(.gray)
}
.padding()
}
}
struct WeatherResponse: Codable {
struct CurrentWeather: Codable {
let temperature: Double
let windspeed: Double
}
let current_weather: CurrentWeather
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
fetchWeather() に async を付ける 非同期処理を行う関数になる
Task { await fetchWeather() } SwiftUI のボタン内で非同期関数を呼ぶための安全な方法
try await URLSession.shared.data(from:) 通信が完了するまで待機(コールバック不要)
await MainActor.run { … } UI更新は常にメインスレッドで行う
うん、asyncは他の言語でもよく出てくるのでわかりやすい。