I need my JSON data to be translated to a list as an output for an app I am creating.
I have found this tutorial, which seems to be using some old elements like "BindableObject":
https://www.youtube.com/watch?v=ri1A032zfLo
As far as I've checked several times, I went word for word in the NetworkingManager file being described from 1:52 in the video (just changing the names and the URL). My code:
import Foundation
import SwiftUI
import Combine
/*BindableObject was renamed to ObservableObject */
class NetworkingManager: ObservableObject{
var didChange: PassthroughSubject <NetworkingManager, Never>
var gitHubList = Root(items: []){
didSet{
didChange.send(self)
}
}
init() {
guard let url = URL(string: "https://api.github.com/search/repositories?q=CoreData&per_page=20") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in guard let data = data else { return }
let gitHubList = try! JSONDecoder().decode(GitHubAPIlist.self, from: data)
DispatchQueue.main.async {
self.gitHubList = gitHubList
}
}.resume()
}
}
I get 2 errors:
'self' captured by a closure before all members were initialized
on the line with URLSession and
Return from initializer without initializing all stored properties
on the line with the } after the .resume() command
Are there some obsolete syntaxes in the code or am I missing something?
CodePudding user response:
You declared the subject but didn't initialize it
var didChange = PassthroughSubject<NetworkingManager, Never>()
However actually you don't need the subject, mark gitHubList as @Published (and delete the subject).
And if you are only interested in the items declare
@Published var gitHubList = [Repository]()
and assign
DispatchQueue.main.async {
self.gitHubList = gitHubList.items
}
The @Published property wrapper will update the view.
In the view declare NetworkingManager as @StateObject
@StateObject private var networkManager = NetworkingManager()
and in the rendering area refer to
List(networkManager.gitHubList...
Notes:
- Forget the tutorial , the video is more than two years old which are ages in terms of Swift(UI)'s evolution speed.
- Ignoring errors and force unwrapping the result of the JSON decoder is very bad practice. Handle the potential URLSession error and catch and handle the potential decoding error.
CodePudding user response:
try something like this approach, to get you data from github. Works very well for me:
class NetworkingManager: ObservableObject{
@Published var gitHubList: [Item] = []
init() {
loadData()
}
func loadData() {
guard let url = URL(string: "https://api.github.com/search/repositories?q=CoreData&per_page=20") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in
guard let data = data else { return }
do {
let response = try JSONDecoder().decode(Root.self, from: data)
DispatchQueue.main.async {
self.gitHubList = response.items
}
} catch {
print("error: \(error)")
}
}.resume()
}
}
struct Root: Codable {
let totalCount: Int
let incompleteResults: Bool
let items: [Item]
enum CodingKeys: String, CodingKey {
case totalCount = "total_count"
case incompleteResults = "incomplete_results"
case items
}
}
struct Item: Identifiable, Codable {
let keysURL, statusesURL, issuesURL: String
let id: Int
let url: String
let pullsURL: String
// ... more properties
enum CodingKeys: String, CodingKey {
case keysURL = "keys_url"
case statusesURL = "statuses_url"
case issuesURL = "issues_url"
case id
case url
case pullsURL = "pulls_url"
}
}
struct ContentView: View {
@StateObject var netManager = NetworkingManager()
var body: some View {
List {
ForEach(netManager.gitHubList) { item in
Text(item.url)
}
}
}
}
