MCMatan MCMatan - 3 months ago 19
Swift Question

Make class type a Dictionary key (Equatable, Hashable)

Say I have a class named

LivingCreature

And other classes that inherit from it:


  • Human

  • Dog

  • Alien



This is what I'm trying to accomplish:

let valueForLivingCreature = Dictionary<Alien, String>


And access it like so:

let alienValue = livingCreatureForValue[Alien]


But this means the class should conform to
Equatable
and
Hashable
, but the class itself, not the class instance.
I've tried various ways of accomplishing this, but no luck.

As a compromise I've came up with is:

typealias IndexingValue = Int
class LivingCreature {
static var indexingValue: IndexingValue = 0
}


And then I can use the class as a key like so:

let livingCreatureForValue = Dictionary<IndexingValue, String>


Access:

let alienValue = livingCreatureForValue[Alien.indexingValue]


But, this way the IndexingValue should be set per class, by hand.
I would like to make a hash from the class itself like so:

class LivingCreature {
static var indexingValue: IndexingValue {
return NSStringFromClass(self).hash
}
}


This is not possible because
self
is not accessible is static var.

My question is, is there a better way of addressing this kind of issue?

Edit:

@Paulw11 Asked me why not make LivingCreature confirm to Equatable and Hashable,
The reason is I would not be able to access the value by the class type reference.
I would have to alloc an instance every time:

let alienValue = livingCreatureForValue[Alien()]


I do not want to call "Alien()" every time for finding a value.
And the component that uses it, doesn't care about the livingCreature instance, only about the class type.

Answer

I assume your are trying something like:

let valueForLivingCreature = Dictionary<LivingCreature.Type, String>

and:

let alienValue = valueForLivingCreature[Alien.self]

Then you can use ObjectIdentifier:

class LivingCreature {
    class var classIdentifier: ObjectIdentifier {
        return ObjectIdentifier(self)
    }
    //...
}

class Human: LivingCreature {
    //...
}

class Dog: LivingCreature {
    //...
}

class Alien: LivingCreature {
    //...
}

let valueForLivingCreature: Dictionary<ObjectIdentifier, String> = [
    Human.classIdentifier: String(Human),
    Dog.classIdentifier: String(Dog),
    Alien.classIdentifier: String(Alien),
]

let alienValue = valueForLivingCreature[Alien.classIdentifier] //->"Alien"

But in most use cases when you want to use meta-class as a dictionary key, you can find another way around:

class LivingCreature {
    class var classValue: String {
        return String(self)
    }
    //...
}

class Human: LivingCreature {
    //...
    //Override `classValue` if needed.
}

class Dog: LivingCreature {
    //...
}

class Alien: LivingCreature {
    //...
}

let alienValue = Alien.classValue //->"Alien"
Comments