Home > OS >  JSON API transfer data in Swift
JSON API transfer data in Swift

Time:05-03

How to pass data from json api to static func getAllStats()

I need to transfer only 2 parameters P and W from JSON

look at the screenshot

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()
        }
    }
}
  • Related