NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: Need help with JSON to struct.

Forums > SwiftUI

Dear team

I'm on day 61 of SwiftUI in 100 days.

I'm just trying to write a bit of code myself but i'm struggling.

I think most of my code is working (despite not being able to build it - so any comments welcome!)

However it wont build.

In my @main app file I get the error: 'ContentView' initializer is inaccessible due to 'private' protection level

It's wanting me to put in some initial result for my results variable decared in my ContentView. However i have no initial values as this needs to come from JSON. There must be a way to create an instance of my struct without needing to fill it!

Any help making this work would be reallly appreciated. In my list view i've only got one variable showing, i'll add more later but i need the first bit to work obviously!

thank you

//
//  TestBinsApp.swift
//  TestBins
//
//  Created by Layth Tameem on 30/09/2022.
//

import SwiftUI

@main
struct TestBinsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView() 
            //error here is 1. 'ContentView' initializer is inaccessible due to 'private' protection level
            //error 2 is: Missing argument for parameter 'results' in call
            //it wants me to fix it with: Insert 'results: <#DataFormatted#>'
        }
    }
}
//
//  ContentView.swift
//  TestBins
//
//  Created by Layth Tameem on 30/09/2022.
//

import SwiftUI

struct DataFormatted: Codable {
     var deliveryPoints: [DeliveryPoint]
     var deliveryPointCount: Int
     var postalCounty: String
     var traditionalCounty: String
     var town: String
     var postcode: String // <-- postcode

     enum CodingKeys: String, CodingKey {
         case deliveryPoints = "delivery_points"
         case deliveryPointCount = "delivery_point_count"
         case postalCounty = "postal_county"
         case traditionalCounty = "traditional_county"
         case town, postcode
     }
 }

 struct DeliveryPoint: Identifiable, Codable {
     let id = UUID()
     var organisationName: String
     var departmentName: String
     var line1: String?
     var line2: String?
     var line3: String?
     var udprn: String
     var dps: String

     enum CodingKeys: String, CodingKey {
         case organisationName = "organisation_name"
         case departmentName = "department_name"
         case line1 = "line_1"
         case line2 = "line_2"
         case line3 = "line_3"
         case udprn, dps
     }
 }

struct ContentView: View {
    @State private var results: DataFormatted

    var body: some View {
        VStack{
            List{
                Text(results.postcode)
                }
            .task {
                await loadData()

            }
        }

        }

    func loadData() async {

        guard let url = URL(string: "https://pcls1.craftyclicks.co.uk/json/rapidaddress?key=d2be6-297a1-a60ec-0840a&postcode=aa11aa&response=data_formatted") else {
            print("Invalid URL")
            return
        }

        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "GET"

        do {
            let (data, _) = try await URLSession.shared.data(for: request)
            let decoder = JSONDecoder()
            //this next line was to convert form snake case to camel but not all the keys were snake so i used coding keys instead
           // decoder.keyDecodingStrategy = .convertFromSnakeCase 

            let decodedResponse = try decoder.decode(DataFormatted.self, from: data)

           results = decodedResponse

        } catch let jsonError as NSError {
            print("JSON decode failed: \(jsonError)")
          }
    }
}

The test JSON data is as follows:

{
    "delivery_points":[
        {
            "organisation_name":"THE BAKERY",
            "department_name":"",
            "line_1":"1 HIGH STREET",
            "line_2":"CRAFTY VALLEY",
            "udprn":"12345678",
            "dps":"1A"
        },
        {
            "organisation_name":"FILMS R US",
            "department_name":"",
            "line_1":"3 HIGH STREET",
            "line_2":"CRAFTY VALLEY",
            "udprn":"12345679",
            "dps":"1B"
        }
    ],
    "delivery_point_count":2,
    "postal_county":"POSTAL COUNTY",
    "traditional_county":"TRADITIONAL COUNTY",
    "town":"BIG CITY",
    "postcode":"AA1 1AA"
}

   

can you give it a try for your content View

import SwiftUI

struct DataFormatted: Codable {
     var deliveryPoints: [DeliveryPoint]?
     var deliveryPointCount: Int = 0
     var postalCounty: String = ""
     var traditionalCounty: String = ""
     var town: String = ""
     var postcode: String = "" // <-- postcode

     enum CodingKeys: String, CodingKey {
         case deliveryPoints = "delivery_points"
         case deliveryPointCount = "delivery_point_count"
         case postalCounty = "postal_county"
         case traditionalCounty = "traditional_county"
         case town, postcode
     }
 }

 struct DeliveryPoint: Identifiable, Codable {
     let id = UUID()
     var organisationName: String
     var departmentName: String
     var line1: String?
     var line2: String?
     var line3: String?
     var udprn: String
     var dps: String

     enum CodingKeys: String, CodingKey {
         case organisationName = "organisation_name"
         case departmentName = "department_name"
         case line1 = "line_1"
         case line2 = "line_2"
         case line3 = "line_3"
         case udprn, dps
     }
 }

struct ContentView: View {
    @State  var results: DataFormatted

    var body: some View {
        VStack{
                   List{
                       Text(results.postcode)
                       }
                   .task {
                       await loadData()

                   }
               }

               }

           func loadData() async {

               guard let url = URL(string: "https://pcls1.craftyclicks.co.uk/json/rapidaddress?key=d2be6-297a1-a60ec-0840a&postcode=aa11aa&response=data_formatted") else {
                   print("Invalid URL")
                   return
               }

               var request = URLRequest(url: url)
               request.setValue("application/json", forHTTPHeaderField: "Content-Type")
               request.httpMethod = "GET"

               do {
                   let (data, _) = try await URLSession.shared.data(for: request)
                   let decoder = JSONDecoder()
                   //this next line was to convert form snake case to camel but not all the keys were snake so i used coding keys instead
                  // decoder.keyDecodingStrategy = .convertFromSnakeCase

                   let decodedResponse = try decoder.decode(DataFormatted.self, from: data)

                  results = decodedResponse

               } catch let jsonError as NSError {
                   print("JSON decode failed: \(jsonError)")
                 }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(results: DataFormatted())
    }
}

   

Its a good try and I thought of something similar but it doesn't change. It still says the same error... Thank you for trying!

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

are you sure, i just tried this code and it gives AA1 1AA in the list, i hope there no other dependecy any where else..

   

I changed my main app file to:

import SwiftUI

@main
struct TestBins2App: App {
    var body: some Scene {
        WindowGroup {
            ContentView(results: DataFormatted()) // <- I change this from ContentView()
        }
    }
}

and it worked!

Thank you for your help!

1      

Layth! In πŸ₯ hospital, a crew πŸ‘©πŸ»β€βš•οΈπŸ§‘πŸΎβ€βš•οΈπŸ§‘πŸΌβ€βš•οΈ might cleanup for you after surgery 🩻. Here you have to do it yourself πŸͺ£πŸ§Ή!

Please mark Amit's answer as "Correct" βœ….

   

@Obelix: I usually get annoyed by trite overuse of emoji, but yours gave me a nice chuckle! Tnx!

1      

@Obelisk - haha maybe its because my day job is am anaesthetist Andy I'm used to it!!

ill try to clean it up! do tou mean the layout and spacing etc are messy or the code is not clean/good?

   

Dr Layth asks:

I'll try to clean it up! do you mean the layout and spacing etc are messy or the code is not clean/good?

Not at all. What I meant was marking an answer as "Correct". Since this is your patient, only you can select the correct answer. But marking it as correct is a necessary step. This way your colleagues don't continue to visit this patient for a diagnosis.

By marking it as cured, i mean correct we know that the underlying condition has been diagnosed, standard protocols are in place, and the patient is on the road to recovery.

1      

OH! HAHA - yeh fair enough!

cheers @Obelix!

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.