Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access to Dictionary values inside Array in swift

I have an array with data for my TableView sections

let menuItems : Dictionary<String,Dictionary<String,String>>[] = [
    [
        "data" : [
            "name":"test",
            "image":"test.png"
        ]
    ],
    [
        "data" : [
            "name":"test2",
            "image":"test2.png"
        ]
    ]
]

I'm trying to access it by using subscript

func tableView(tableView: UITableView!, titleForHeaderInSection section: Int) -> String! {
    return menuItems[section]["data"]["name"]
}

and have the error

Could not find member 'subscript'

I have read a lot of similar questions on stackoverflow, but still haven't understood how to fix it. I tried to unwrap with "!" symbol and used another variables - no result.

Could you explain how does it works, please?

like image 807
John Kakon Avatar asked May 08 '26 00:05

John Kakon


1 Answers

println(menuItems[0]["data"]!["name"])

Short answer: menuItems[0]["data"] returns an optional dictionary.

You can look at the below REPL output to understand the issue.

  1. sets up the object.
  2. shows that the array returns a regular dictionary. If the index is out of range, an error will be thrown instead of returning an optional dictionary.
  3. shows that accessing a key in a dictionary that does not exist will return nil
  4. shows that accessing a key in a dictionary will return an optional of its value type. For instance, if a dictionary is storing Strings in its values, it will return a String? when indexed into.
  5. shows that we cannot use subscripts on an optional dictionary.
  6. shows that we can force the optional dictionary to be a dictionary because we know it is not nil. The REPL shows us that the new return type is Dictionary<String, String>
  7. shows that we can then use subscripts to get at the innermost values, and this returns an optional string to us. Optional strings are printable, so my code above doesn't need a second !.
  8. shows that if we force both dictionary return types to their non-optional types, we get a regular value back (a string).

In real code, you would probably want to check for optionals, and handle nils accordingly.

1> let menu: Dictionary<String, Dictionary<String, String>>[] = [["dict1" : ["key" : "val"]], ["dict2" : ["key" : "val"]]]

menu: Dictionary<String, Dictionary<String, String>>[] = size=2 {
  [0] = {
    [0] = {
      key = "dict1"
      value = {
        [0] = {
          key = "key"
          value = "val"
        }
      }
    }
  }
  [1] = {
    [0] = {
      key = "dict2"
      value = {
        [0] = {
          key = "key"
          value = "val"
        }
      }
    }
  }
}

2> menu[0]

$R1: Dictionary<String, Dictionary<String, String>> = {
  [0] = {
    key = "dict1"
    value = {
      [0] = {
        key = "key"
        value = "val"
      }
    }
  }
}

3> menu[0]["key"]

$R2: Dictionary<String, String>? = nil

4> menu[0]["dict1"]

$R3: Dictionary<String, String>? = Some {
  [0] = {
    key = "key"
    value = "val"
  }
}

5> menu[0]["dict1"]["key"]

REPL:6:1: error: could not find member 'subscript'
menu[0]["dict1"]["key"]
^~~~~~~~~~~~~~~~~~~~~~~

6> menu[0]["dict1"]!

$R4: Dictionary<String, String> = {
  [0] = {
    key = "key"
    value = "val"
  }
}

7> menu[0]["dict1"]!["key"]

$R5: String? = "val"

8> menu[0]["dict1"]!["key"]!

$R6: String = "val"
like image 51
Millie Smith Avatar answered May 10 '26 21:05

Millie Smith