Search code examples
xcodeswiftdictionaryhashable

Can metatype (.Type) be used as Key in Dictionary?


I have something like this:

class Lumber { }
class Fruit { }

enum Size {
    case small
    case medium
    case large
}

let lumberSize = [
    Size.small: "2x4",
    Size.medium: "4x6",
    Size.large: "6x10"
]

let fruitSize = [
    Size.small: "grape",
    Size.medium: "apple",
    Size.large: "watermelon"
]

let size:[AnyObject.Type:Dictionary] = [
    Lumber.Type: lumberSize,
    Fruit.Type: fruitSize
]

On my size dictionary definition, I get this real-time error from Xcode Editor:

Type 'AnyObject.Type' does not conform to protocol 'Hashable'

How do I accomplish what I am trying to do with size? That is, how do I create a dictionary linking types to their specific size dictionaries?

I am thinking that ObjectIdentifier would help me since it is Hashable but I do not know how to use it, or if it is the right choice.


Solution

  • Hashable is a protocol that ObjectIdentifier implements. This means ObjectIdentifier(Lumber.Type) is hashable, not that Lumber.Type is. You could try changing your code to use ObjectIdentifier, as in:

    class Lumber { }
    class Fruit { }
    
    enum Size {
        case small
        case medium
        case large
    }
    
    let lumberSize = [
        Size.small: "2x4",
        Size.medium: "4x6",
        Size.large: "6x10"
    ]
    
    let fruitSize = [
        Size.small: "grape",
        Size.medium: "apple",
        Size.large: "watermelon"
    ]
    
    let size:[ObjectIdentifier:[Size:String]] = [
        ObjectIdentifier(Lumber.self): lumberSize,
        ObjectIdentifier(Fruit.self): fruitSize
    ]
    
    let t = size[ObjectIdentifier(Lumber.self)]
    let s = t?[.small]
    print(s ?? "no s?")
    

    This compiles and prints "2x4", but I'm not sure if it meets your specific needs. Personally, I would just use the string version of the class name as the key - String(Lumber). i.e.:

    let size:[String:[Size:String]] = [
        String(describing:Lumber.self): lumberSize,
        String(describing:Fruit.self): fruitSize
    ]
    
    let t = size[String(describing:Lumber.self)]
    let s = t?[.small]
    print(s ?? "no s?")