0

Super newbie here. I have this sample json named items_tmp.json that is embedded in my project

[
    {
        "id": "1",
        "name": "hello",
        "description": "aaa"
    },
    {
        "id": "2",
        "name": "world",
        "description": "bbb"
    }
]

I am trying to read file, make it into a dictionary object so i could itterate through the data and call elements by key name.

So far I have this within viewDidLoad:

    let itemsListJson:String = "jsons/items_tmp"
    guard let urlItems = Bundle.main.url(forResource: itemsListJson, withExtension: "json") else { return }

    do{
        let dataItems = try Data(contentsOf: urlItems)
        let jsonItems = try JSONSerialization.jsonObject(with: dataItems, options: .mutableContainers)
        guard let arrayItems = jsonItems as? [Any] else {return}
        print(arrayItems.count)
        for i in 0 ..< arrayItems.count  {
            let max_damage = arrayItems[i]
            print(max_damage)
        }
    }
    catch{
        print(error)
    }

resulting with the following output:

2
{
description = aaa;
id = 1;
name = hello;
}
{
description = bbb;
id = 2;
name = world;
}

So I get my info but it is nor in key-->value formation

When I try getting a specific value by key like so

let name = arrayItems[i].name

I get: type any has no member name

on the other hand if I change the following line to dictionary structure:

 guard let arrayItems = jsonItems as? [String: Any] else {return}

I get no data.

Not sure how its done.

Any help will be greatly appreciated

Long Luong
  • 764
  • 2
  • 14
  • 28
Johny D Good
  • 427
  • 1
  • 8
  • 26

3 Answers3

2

Just create a Item struct that conforms to Codable and pass an Item array type to the json decoder:

struct Item: Codable {
    let id: String
    let name: String
    let info: String
    private enum CodingKeys: String, CodingKey {
        case id, name, info = "description"
    }
}

Playground testing:

let dataItems = Data("""
[
    {
        "id": "1",
        "name": "hello",
        "description": "aaa"
    },
    {
        "id": "2",
        "name": "world",
        "description": "bbb"
    }
]
""".utf8)

do {
    let items = try JSONDecoder().decode([Item].self, from: dataItems)
    for item in items {
        print("id:", item.id)
        print("name:", item.name)
        print("description:", item.info)
    }
} catch {
    print(error)
}

id: 1

name: hello

description: aaa

id: 2

name: world

description: bbb

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • thanks but not practical in my case since data must come from an embedded json file and not embedded in code. – Johny D Good Dec 30 '17 at 21:34
  • That would be easy. You can read if from file or simply convert your object to data using JSONSerialization – Leo Dabus Dec 30 '17 at 21:36
  • If you post your itemsListJson string I can show you how to decode it – Leo Dabus Dec 30 '17 at 21:40
  • Thanks, I appreciate your help. Not sure I understand. itemsListJson string is "jsons/items_tmp". Or did you mean to upload the json file itself. – Johny D Good Dec 30 '17 at 22:11
  • I used the json data you posted in your question. Do you need to encode or decode the JSON ? – Leo Dabus Dec 30 '17 at 22:13
  • If you don't post your actual JSON data (string) I can't really help. I already showed how to decode the data so you can just read it from the json fileURL from your Bundle and decode it. I don't know what do you mean by "come from an embedded json file". If the array it is just part of the JSON show your actual json – Leo Dabus Dec 30 '17 at 22:19
  • I see. I used this: let responseString = String(data: dataItems, encoding: .utf8) and got: responseString = Optional("[\n\t{\n\t\t\"id\": \"1\",\n\t\t\"name\": \"hello\",\n\t\t\"description\": \"aaa\"\n\t},\n\t{\n\t\t\"id\": \"2\",\n\t\t\"name\": \"world\",\n\t\t\"description\": \"bbb\"\n\t}\n]\n") – Johny D Good Dec 30 '17 at 22:21
  • Just ignore my string and use your `dataItems` object – Leo Dabus Dec 30 '17 at 22:21
  • Maybe i used wrong phrase of words. English is not my mother tongue. In embedded json I just meant that i have a json file as part of the projects. That is the whole json for now. When I figure out how to read it as a dictionary I will change the json, but the formation will still be the same. – Johny D Good Dec 30 '17 at 22:26
  • You don't need to read it as dictionary. Just use the data you read from file – Leo Dabus Dec 30 '17 at 22:28
  • `do { let dataItems = try Data(contentsOf: urlItems) let items = try JSONDecoder().decode([Item].self, from: dataItems) }` – Leo Dabus Dec 30 '17 at 22:29
0

You will get "type any has no member name" because you nowhere define it. I smell a possible duplicate of the following, because your json is a array, not a dictionary...

Convert JSON String to Swift Dictionary

How to convert a json of objects to dictionary

Convert a JSON string to Dictionary in Swift 3

dotkomm
  • 11
  • 5
0

Thanks to all answers, this is what I was looking for:

    let itemsListJson:String = "jsons/items_tmp"
    guard let urlItems = Bundle.main.url(forResource: itemsListJson, withExtension: "json") else { return }
    do{
        let dataItems = try Data(contentsOf: urlItems)
        let jsonItems = try JSONSerialization.jsonObject(with: dataItems, options: .mutableContainers)
        guard let arrayItems = jsonItems as? [Any] else {return}
        for i in 0 ..< arrayItems.count  {
            let tmp = arrayItems[i] as! [String: Any]
            print(tmp["id"]!)
            print(tmp["name"]!)
            print(tmp["description"]!)
        }
    }
    catch{
        print(error)
    }

This helped me understand what I was doing wrong. Your JSON is an array of dictionaries. Cast accordingly. – rmaddy So basically I get the json as an array, iterate through the array and in turn treat each array element as a dictionary so i can use the key->value property

Johny D Good
  • 427
  • 1
  • 8
  • 26