JSON Decoded data not getting returned to be used.

I created a class and a function to make an API call and return some data. I get the data back in the console, but I'm not able to use the data and I think it's because I'm not completing the data correctly. The data being returned is surrounded by { } instead of [ ].

The function looks like this:

Code Block
func getBusinessInfo(completion: @escaping ([Welcome]) -> ()) {
...
       let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
...
       if let yelpbusinessinfo = data {
        let decoder = JSONDecoder()
        let yelpbusinessinfo = try? decoder.decode(Welcome.self, from: yelpbusinessinfo)
        print(yelpbusinessinfo?.reviews[1].text)
        completion(yelpbusinessinfo!)
      }


At completion(yelpbusinessinfo!) I get the following error in the compiler and I'm assuming it has to do with how the data is being returned.

Cannot convert value of type 'Welcome' to expected argument type '[Welcome]'

Any help on what the proper format should be?

You should not use forced-unwrapping (!) for the returned value from try?. If some error occurs, your app will crash.
Also, I recommend you not to use try?, as it disposes error info.

Cannot convert value of type 'Welcome' to expected argument type '[Welcome]'

You are passing Welcome.self to decode, so the type of yelpbusinessinfo is Welcome?, not an Array of Welcome.
(Better avoid using the same identifier for two different things...)

The type of the parameter of completion should be Welcome (or Welcome?).

An example:
Code Block
func getBusinessInfo(completion: @escaping (Welcome?) -> ()) { //<-
//...
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
//...
if let yelpbusinessdata = data {
let decoder = JSONDecoder()
do {
let yelpbusinessinfo = try decoder.decode(Welcome.self, from: yelpbusinessdata)
print(yelpbusinessinfo.reviews[1].text)
completion(yelpbusinessinfo) //<-
} catch {
print(error)
//...
completion(nil) // On error pass `nil` to completion handler.
}
}
}
//...
}



Thanks OOPer! Does doing it the way you show differ with the error catching I have in place?

Code Block
       if let error = error {
        print("Error took place \(error)")
        return
      }


Do I declare my state as @State var yelpbusinessinfo: [Welcome] = [] or because it's not an array

Thanks @OOPer! Does doing it the way you show differ with the error catching I have in place?

Code Block
       if let error = error {
        print("Error took place \(error)")
        return
      }


Do I declare my state as @State var yelpbusinessinfo: [Welcome] = [] or because it's not an array

Does doing it the way you show differ with the error catching I have in place?

Yes. Your if let catches the error detected while communications, catch in my code catches the decoding error.
A server may return non-JSON response with successful communications for some occasions.

Do I declare my state as @State var yelpbusinessinfo: [Welcome] = [] or because it's not an array 

Hard to say anything under the current info given.


That's fair. I'm still struggling to understand why I'm getting this error Cannot assign value of type 'Welcome?' to type '[Welcome]'. My guess is that is has to how the data is being returned because it's not an array 1[ ] and dictionary { }?

My guess is that is has to how the data is being returned because it's not an array 1[ ] and dictionary { }?

In JSON, dictionary-like structure is called object. But the terminology is not important here. When you decode a JSON object passing a proper Decodable struct. Passing Welcome.self, getting an instance of Welcome, not an array.

In JSON, dictionary-like structure is called object. 

Thank you! I'm learning here so this is helpful. I appreciate your patience as well.

I'm sort of struggling to grasp what you're saying. How is this different when a response is [ ] vs { }?

In my view I have Welcome declared as @State var yelpbusinessdata: [Welcome] = [] and I'm calling the data as

Code Block
 List(yelpbusinessdata) { review in
..
}


Code Block
               .onAppear{
                print("on appear calling data")
                Yelp().getBusinessInfo {
                  (yelpbusinessinfo) in
                  self.yelpbusinessdata = yelpbusinessinfo
                  print("we got yelp reviews")
                }
              }

Accepted Answer

I'm sort of struggling to grasp what you're saying. How is this different when a response is [ ] vs { }?  

[] represents a JSON array, when using Codable, it usually is decoded to an Array of some struct.

In my view I have Welcome declared as @State var yelpbusinessdata: [Welcome] = [] 

Your API returns a single object, so declaring your yelpbusinessdata as an Array does not make sense.

I guess you want to show the reviews in Welcome.

Then, you should declare the property  @State var yelpbusinessdata: Welcome? = nil, -- not an Array.
And use it as as something like this:
Code Block
List(yelpbusinessdata?.reviews ?? []) { review in
//...
}


You may need to modify some parts or may need to show more info.
Sorry last question ;). Am I accessing the data as

Code Block
             List(yelpbusinessdata?.reviews ?? []) { review in
...
                    Text(yelpbusinessdata?.reviews[review].user.name)`
}

  Am I accessing the data as
Please remember, you are not revealing any details of your struct Welcome.

My best guess, it should be:
Code Block
                    Text(review.user.name)


Sorry! I had thought I revealed those. Here they are

Code Block
// MARK: - Welcome
struct Welcome: Codable, Identifiable {
  let id = UUID()
  let reviews: [Review]
  let total: Int
  let possibleLanguages: [String]
  enum CodingKeys: String, CodingKey {
    case reviews, total
    case possibleLanguages = "possible_languages"
  }
}
// MARK: - Review
struct Review: Codable, Identifiable {
  let id: String
  let url: String
  let text: String
  let rating: Int
  let timeCreated: String
  let user: User
  enum CodingKeys: String, CodingKey {
    case id, url, text, rating
    case timeCreated = "time_created"
    case user
  }
}
// MARK: - User
struct User: Codable {
  let id: String
  let profileURL: String
  let imageURL: String
  let name: String
  enum CodingKeys: String, CodingKey {
    case id
    case profileURL = "profile_url"
    case imageURL = "image_url"
    case name
  }
}


 Here they are

Thanks.
Seeing your code, seems my guess was right and the following code should work:
Code Block
List(yelpbusinessdata?.reviews ?? []) { review in
//...
Text(review.user.name)
}


JSON Decoded data not getting returned to be used.
 
 
Q