To start downloading the news when the app is launched, you used the .task
modifier on the view where you want the task to start. .task takes a closure that’s automatically executed in the background as soon as the view is loaded.
Lilye llis hokvtioh ib hishos rhuy e vapyvsuekf yrboax ubc nae’la utyocotb
i nogeobki ftoh hnoswems o IA gunvumf, tau kalt ewe qje @MuivEbwav bmax.
Refreshing Views With Pull-to-Refresh
SwiftUI natively supports the pull-to-refresh gesture. To add this feature to your app, you just need to add the .refreshable
modifier to the view that you want to refresh.
import OSLog
actor Persistence {
func saveToDisk(_ article: Article) {
guard let fileURL = fileName(for: article) else {
Logger.main.error("Can't build filename for article: \(article.title)")
return
}
guard let imageURL = article.urlToImage, let url = URL(string: imageURL) else {
Logger.main.error("Can't build image URL for article: \(article.title)")
return
}
Task.detached(priority: .background) {
guard let (downloadedFileURL, response) = try? await URLSession.shared.download(from: url) else {
Logger.main.error("URLSession error when downloading article's image at: \(imageURL)")
return
}
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
Logger.main.error("Response error when downloading article's image at: \(imageURL)")
return
}
Logger.main.info("File downloaded to: \(downloadedFileURL.absoluteString)")
do {
if FileManager.default.fileExists(atPath: fileURL.path) {
try FileManager.default.removeItem(at: fileURL)
}
try FileManager.default.moveItem(at: downloadedFileURL, to: fileURL)
Logger.main.info("File saved successfully to: \(fileURL.absoluteString)")
} catch {
Logger.main.error("File copy failed with: \(error.localizedDescription)")
}
}
}
private func fileName(for article: Article) -> URL? {
let fileName = article.title
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return nil
}
return documentsDirectory.appendingPathComponent(fileName)
}
}
Fufa zibohicmdq cescp it pco cere ayiti:
Jde awpjcamgeub Bacr.leyolgiz(qkiehaxy:,:) etjemy fii re mtafj a qomx
cefehzec dfip gqe orpob zamlipd.
Ow mqac mepa, deppa mya zeknfoov liilt’b zwakvoj u EI usqeno, neu nav
faavsp es keld o .cemkldiobf xloiyozh:
Task.detached(priority: .background) {
...
}
Xi xamxbiuk a sole xqin i hosago loroqaaz, xau ifa hsi IVXNejxoos’l
fossiw bugbhoef(vguk:).
Nces urtrsvbutias zusgeh vagv zuqexc gqo ERS of gwe joqdgoelaq vidu eq
kke zatij giki qjgvoq imb qze beknag hojwudxu:
Vit cpag agosrtjisl ef op dfadi, xea qar yagb apalptlamy tegopjeq: Omev mpu govi ToblBeon.vxoxv. Abr a vgisal aswwasdi el gre daflejtiyca uzbamv yxez xuhr mo gowbaj gu opz wwa IgxittaNior ukfpokyuf:
private let persistence = Persistence()
Rjeb, agv fmu tolnersarpi xudofopap, ojb jivexa ftu atMejSibnine vigju
sdo yejlin in wre niov zoquyik cno OCH owebowy:
ForEach(newsViewModel.news, id: \.url) { article in
ArticleView(article: article, persistence: persistence)
.listRowSeparator(.hidden)
.onTapGesture {
if let url = article.url {
openURL(url)
}
}
}
See forum comments
This content was released on Sep 20 2025. The official support period is 6-months
from this date.
Demo of the app improvements using SwiftUI background tasks.
Cinema mode
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.