2

I have this json data that I want to consume in Swift 3. I'm learning Swift and building a very basic app that displays the list of items in tableUIView from JSON.

{
  "expertPainPanels" : [
     {
       "name": "User A",
       "organization": "Company A"
     },
     {
       "name": "User B",
       "organization": "Company B"
     }
    ]
}

I'm trying to get this data using Swift 3.

if (statusCode == 200) {
    do{
        let json = try? JSONSerialization.jsonObject(with: data!, options:.allowFragments) // [[String:AnyObject]]

/*
    If I do this: 

    let json = try? JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String:Any]

    if let experts = json?["expertPainPanels"] as! [String: Any] {
    I get "Initializer for conditional binding must have Optional type, not '[String: Any]'"

*/


        // Type 'Any' has no subscript members.
        if let experts = json["expertPainPanels"] as? [String: AnyObject] {

            for expert in experts {
                let name = expert["name"] as? String
                let organization = expert["organization"] as? String
                let expertPainPanel = ExpertPainPanel(name: name, organization: organization)!
                self.expertPainPanels += [expertPainPanel]
                self.tableView.reloadData()
                self.removeLoadingScreen()
            }
        }
     }catch {
          print("Error with Json: \(error)")
        }
     }

It was working fine in Swift 2. I updated to Swift 3 which broke the code. I read several SO, but I still have hard time understanding it. I applied some suggestions including JSON Parsing in Swift 3, but I'm still unable to fix the error I'm getting.

Community
  • 1
  • 1
user1828605
  • 1,723
  • 1
  • 24
  • 63

1 Answers1

7

As of Swift 3, you need to do a cast early on.

This line:

let json = try? JSONSerialization.jsonObject(with: data!, options:.allowFragments)

Should become this:

let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as? [String : AnyObject]

This is because JSONSerialization now returns Any, which does not implement a variation for the [] operator. Make sure you safely unwrap the cast and take the common measures to ensure you don't crash your program.

Edit: Your code should more or less look like this.

let data = Data()
let json = try JSONSerialization.jsonObject(with: data, options:.allowFragments) as! [String : AnyObject]
if let experts = json["expertPainPanels"] as? [String: AnyObject] {
Andy Ibanez
  • 12,104
  • 9
  • 65
  • 100
  • 1
    Given that you're using `as?`, I'd probably do `if let json = try ... as? [String: AnyObject] { ... }` or `guard let`. – Rob Sep 12 '16 at 22:27
  • Yes. Also consider doing the same with your `data` variable unless you are 100% certain it will never be null (if you are using the network, then you can never be 100% certain). – Andy Ibanez Sep 12 '16 at 22:28
  • As my commented section in the code above in the question show, I get the "Initializer for conditional binding must have Optional type, not '[String: Any]'" error. I get the same error using the same error again. Am I doing something wrong? – user1828605 Sep 12 '16 at 22:45
  • Does your `try` statement still have the question mark `?`? You don't need it, but if you put it you need to do `json?["expertPainPanels"]` – Andy Ibanez Sep 12 '16 at 22:49
  • I realize what I'm telling you is similar to what you have in your comments, but it's compiling fine for me. – Andy Ibanez Sep 12 '16 at 22:50
  • No I removed it. I copied and pasted your code and still get the same error. – user1828605 Sep 12 '16 at 22:50
  • I have edited my question to show more or less what you should have. I played around in a Playground and it's working for me. Ensure you safely deal with the optionals once you get the gist of it. – Andy Ibanez Sep 12 '16 at 22:52
  • Well, this seemed to have gotten rid of the error I was getting, but now it's giving me other errors for extracting `name` and `organization`. I will select this as the answer since it answers the question. I'll have to play around with how to fix the next error. Thank you so much for your help. :) – user1828605 Sep 12 '16 at 23:01
  • it's pretty easy to fix those errors from here. Casting the initial JSONSerialization to `[String : AnyObject]` was just the tip of the iceberg. If you know those `AnyObject`s are other dictionaries `[String : String]`, you could cast the JSON to `[String : [String: String]]`. You could also do the casts in your loop or use pattern matching. I know it sounds convoluted, but it's much better this way. – Andy Ibanez Sep 12 '16 at 23:06