David Koenig's Blog

News App - SwiftUI - Part I


In Part One we are creating all Models which help us to use the API and more!

In the Models/News.swift File, we create a Results struct. The Results struct has an Array of News. The News are also defined as an struct. Both are Decodable and the News struct is also Identifiable.

import Foundation struct Results: Decodable { let articles: [News] } struct News: Decodable, Identifiable { var id: String { return publishedAt } let publishedAt: String let title: String let description: String let urlToImage: String? let url: String? }

The News struct has to have a id to be Identifiable. I linked the id with the publishedAt constant. All constants in both of the structs are defined by the JSON of the news api url. They have to be named exactly the same.

The Models/NetworkManager.swift File is the core for retrieving the data from the JSON Url.

import Foundation class NetworkManager: ObservableObject { @Published var news = [News]() func fetchData() { if let url = URL(string: "https://newsapi.org/v2/top-headlines?country=de&apiKey=05f24edac22347af992881b990f47934") { let session = URLSession(configuration: .default) let task = session.dataTask(with: url) { (data, response, error) in if error == nil { let decoder = JSONDecoder() if let safeData = data { do { let results = try decoder.decode(Results.self, from: safeData) DispatchQueue.main.async { self.news = results.articles } } catch { print(error) } } } } task.resume() } } }

In the Network Manager File we decode the data from the news api url. Here you have to implement your own API-Key. The class is an Observable Object, so the class will be observed, when Changes happen. The news Variable is marked as @Published.

The Models/ImageLoader.swift File helps us to load Images from a url.

import Foundation class ImageLoader: ObservableObject { @Published var data: Data? init(urlString:String) { guard let url = URL(string: urlString) else { return } let task = URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data else { return } DispatchQueue.main.async { self.data = data } } task.resume() } }

It behaves similar as the Network Manager, because the image url is also a path.

You can download the project at Github:

David Koenig