How to pass data from json api to static func getAllStats()
I need to transfer only 2 parameters P
and W
from JSON
struct Stat: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
var p: String
var w: String
let t: String
}
extension Stat {
static func getAllStats() -> [Stat] {
return [
Stat(image: "1", name: "Name1", p: "", w: "", t: "12"),
Stat(image: "71", name: "Name2", p: "", w: "", t: "13"),
Stat(image: "2", name: "Name3", p: "", w: "", t: "14")
]
}
}
class Api {
func getPost(completion: @escaping ([Stat]) -> ()) {
guard let url = URL(string: "") else {return}
URLSession.shared.dataTask(with: url) { (data, _, _) in
let posts = try! JSONDecoder().decode([Stat].self, from: data!)
DispatchQueue.main.async {
completion(posts)
}
}
.resume()
}
}
CodePudding user response:
It is not clear to me with what criteria you will be inserting the variables p
and w
from an array of Stat
within other objects of type Stat
: do they need to match the id? Do they need to be read in order?
The code I propose here below creates a dedicated struct
only for those 2 variables, I called it PW
. This will avoid mixing the type you use in your project with the type downloaded from the API. PW
is the type that will be decoded.
p
and w
coming from the api are injected into the Stat
object based on the order of the downloaded JSON just for example purposes - however, this is not the best practice, so I recommend to adapt your code accordingly.
The example uses async
to avoid completion handlers and DispatchQueue
, but that is not necessary - just use your favourite approach.
// This is where the API will store the downloaded values
struct PW: Codable {
let p: String?
let w: String?
}
struct Stat: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
// Replace 2 variables of type string with one variable of type PW
var pw: PW
let t: String
}
extension Stat {
// This will allow the code to read p and w in a convenient way
var p: String { pw.p ?? "" }
var w: String { pw.w ?? "" }
// async just to match the function in the Api class, but you
// can use your own code
static func getAllStats() async -> [Stat] {
// Get the array of PW (with p and w values) from the api
let pws = await Api().getPost()
return [
// Each object will store p and w values based on the order received:
// this is NOT a best practice, a clear and unique criteria should be used
Stat(image: "1", name: "Name1", pw: pws[0], t: "12"),
Stat(image: "71", name: "Name2", pw: pws[1], t: "13"),
Stat(image: "2", name: "Name3", pw: pws[2], t: "14")
]
}
}
// This class is just for example purposes, implement your own code as you wish
class Api {
// async just to avoid completion and DispatchQueue
func getPost() async -> [PW] {
guard let url = URL(string: "https://...") else { return [] }
let request = URLRequest(url: url)
do {
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("Error: HTTP response =\n\(response.debugDescription)")
return []
}
// Decode type PW, not Stat
let posts = try! JSONDecoder().decode([PW].self, from: data)
return posts
} catch {
print("Oops: something went wrong!")
return []
}
}
}
// Example of a view, just to show how to use the code
struct MyView: View {
@State private var stats = [Stat]()
var body: some View {
VStack {
ForEach(stats) { stat in
VStack {
Text(stat.name)
Text(stat.p)
Text(stat.w)
}
}
}
.task {
stats = await Stat.getAllStats()
}
}
}