Nijar
Nijar

Reputation: 81

In Swift getting error Ambiguous reference to member 'subscript'

Required extension for Dictionary as to get text key value if exist.

Implemented below code and it is successfully compiled:

extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject {
    func getValueForKeyPath(keyValue: String) -> String {
        return ((self["item_qty"] as? Dictionary<String, String>) ?? ["": ""])?["text"] ?? ""
    }
}

But when I did small change in method getting error as:

"Ambiguous reference to member 'subscript' "

extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject {
    func getValueForKeyPath(keyValue: String) -> String {
        return ((self[keyValue] as? Dictionary<String, String>) ?? ["": ""])?["text"] ?? ""
    }
}

Please correct me if I am doing anything wrong here.

Upvotes: 2

Views: 1227

Answers (2)

James W
James W

Reputation: 11

While the answer by @Hoa compiles, it'll crash under certain circumstances (i.e. when Dictionary.Key is not a String).

A better solution might be to use one of the init(...) methods from the ExpressibleByStringLiteral protocol.

Notice the extra generic constraint: Key.StringLiteralType == String. This allows us to use keyValue to instantiate a Key object and then use that in self[key].
I think we can assume pretty much all strings used are String, so this shouldn't affect anything.

extension Dictionary where Key: ExpressibleByStringLiteral,
  Key.StringLiteralType == String,
  Value: AnyObject {

  func getValueForKeyPath(keyValue: String) -> String {
    let key = Key(stringLiteral: keyValue) // <-- this is key

    return ((self[key] as? Dictionary<String, String>) ?? ["": ""])?["text"] ?? ""
  }
}

As a side note, it might be worth making that return statement a little clearer and easier to debug:

extension Dictionary where Key: ExpressibleByStringLiteral,
  Key.StringLiteralType == String,
  Value: AnyObject {

  func getValueForKeyPath(keyValue: String) -> String {
    let key = Key(stringLiteral: keyValue)

    guard let dict = self[key] as? Dictionary<String, String>,
      let text = dict["text"]
      else {
        return ""
    }

    return text
  }
}

Upvotes: 1

Duyen-Hoa
Duyen-Hoa

Reputation: 15804

try to cast keyValue to Key. For example:

extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject {
    func getValueForKeyPath(keyValue : String) -> String{
        return ((self[keyValue as! Key] as? Dictionary<String,String>) ?? ["":""])?["text"] ?? ""
    }
}

Upvotes: 5

Related Questions