Это перевод статьи Concurrency Step-by-Step: A Network Request
Это было ошибкой, что я не уделял больше внимания людям, которые только начинают. Я попытаюсь исправить это, углубившись в некоторые основы. Давайте шаг за шагом рассмотрим сетевой запрос с помощью SwiftUI.
Предисловие
Несколько быстрых заметок. Во-первых, я практически опустил всю обработку ошибок. Я сделал это, чтобы сосредоточиться на теме многопоточности. Я также не особо искушенный разработчик SwiftUI, поэтому здесь могут быть некоторые неоптимальные шаблоны.
Важно, что этот пост был написан для Xcode 16. Если вы используете более раннюю версию, некоторые вещи будут работать не так.
Расставляем все по местам
Давайте рассмотрим очень простую программу SwiftUI, которая загружает что-то из сети. Мне нужно было найти бесплатный API для использования, и я остановился на Robohash. Это восхитительное сочетание простого, интересного и необычного.
Поскольку наши данные будут загружаться из сети, нам нужно обработать случай, когда нам нечего отображать. Начнем с небольшого View
, которое может обрабатывать Optional
изображение cgImage
.
struct LoadedImageView: View {
let cgImage: CGImage?
var body: some View {
if let cgImage {
Image(cgImage, scale: 1.0, label: Text("Robot"))
} else {
Text("no robot yet")
}
}
}
Я использовал CGImage
здесь, поэтому этот код может работать без изменений на всех платформах Apple.
Теперь мы можем перейти к более интересным вещам. Давайте создадим View
, которое фактически загружает некоторые данные из сети.
struct RobotView: View {
@State private var cgImage: CGImage?
var body: some View {
LoadedImageView(cgImage: cgImage)
.onAppear {
loadImageWithGCD()
}
}
private func loadImageWithGCD() {
let request = URLRequest(url:
URL(string: "https://robohash.org/hash-this-text.png")!)
let dataTask = URLSession.shared.dataTask(with: request) { data, _, _ in
guard let data else { return }
DispatchQueue.main.async {
let provider = CGDataProvider(data: data as CFData)!
self.cgImage = CGImage(
pngDataProviderSource: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
)
}
}
dataTask.resume()
}
}
Я использовал GCD (Grand Central Dispatch). Надеюсь, это выглядит очень привычно, даже если вы вообще не разбираетесь в многопоточности. Но я все равно хочу отметить, что я использую здесь режим компиляции использования языка Swift 6, и этот код компилируется без ошибок.
Читать далее