10

Can I subclass a Swift Dictionary so that I can pass my custom Dictionary to methods that expect an ordinary Dictionary?

Edit

In my case, I want my custom Dictionary to iterate through its keys in insertion-order.

Community
  • 1
  • 1
Heath Borders
  • 30,998
  • 16
  • 147
  • 256

4 Answers4

9

Swift dictionaries are structs, not classes, so they cannot be subclassed. Ideally, the methods you're working with would be declared to take an appropriately constrained generic CollectionType (or ExtensibleCollectionType, or SequenceType, depending on the situation), rather than specifically a Dictionary.

If that doesn't work for you for whatever reason, you could subclass NSDictionary instead.

(edit) and as Antonio points out, you can do extension Dictionary { … } to add things to the Dictionary struct, which can replace subclassing in some cases.

Catfish_Man
  • 41,261
  • 11
  • 67
  • 84
8

The following is a struct conforming to Collection which delegates to a dictionary. It is fairly easy to modify to any needs.

public struct MyDictionary<Key: Hashable, Value: MyKindOfValue>: Collection {
    public typealias DictionaryType = Dictionary<Key, Value>
    private var dictionary: DictionaryType

    //Collection: these are the access methods
    public typealias IndexDistance = DictionaryType.IndexDistance
    public typealias Indices = DictionaryType.Indices
    public typealias Iterator = DictionaryType.Iterator
    public typealias SubSequence = DictionaryType.SubSequence

    public var startIndex: Index { return dictionary.startIndex }
    public var endIndex: DictionaryType.Index { return dictionary.endIndex }
    public subscript(position: Index) -> Iterator.Element { return dictionary[position] }
    public subscript(bounds: Range<Index>) -> SubSequence { return dictionary[bounds] }
    public var indices: Indices { return dictionary.indices }
    public subscript(key: Key)->Value? {
        get { return dictionary[key] }
        set { dictionary[key] = newValue }
    }
    public func index(after i: Index) -> Index {
        return dictionary.index(after: i)
    }

    //Sequence: iteration is implemented here
    public func makeIterator() -> DictionaryIterator<Key, Value> {
        return dictionary.makeIterator()
    }

    //IndexableBase
    public typealias Index = DictionaryType.Index
}
user3763801
  • 395
  • 4
  • 10
  • Is it right for Swift 3? I can't compile it at all. And Yes I have protocol `MyKindOfValue` – Marcin Kapusta Jun 27 '17 at 17:40
  • Try now. I added the two more subscripts and indices. It goes through now for me. The original was crashing the compiler (!!) for me as well, but if you look at the errors from the compiler (before it crashes) you can deduce what was missing. – user3763801 Jun 27 '17 at 22:55
3

While I agree with most of the comments here (you cannot subclass a Struct, by design it is not a class), you might get the results you want with a custom Struct that conforms to CollectionType (now renamed Collection in Swift 3.0):

struct YourCustomDictionary<Key : Hashable, Value>: Collection {

    private var elements = Dictionary<Key, Value>()
    private var keyOrder = Array<Key>()

    //your custom implementation here 
    //including tracking for your dictionary order

}

You could overload the subscript method so that it appends the key to the keyOrder array. Then provide an iterator that will return (Key, Value) tuples in the correct order.

You probably don't even need to conform to Collection, but this is a good way to get a lot of functionality for free.

promacuser
  • 374
  • 1
  • 15
2

No, dictionaries and arrays in swift are structs, which do not support inheritance. The only way to "personalize" a dictionary is by using extensions.

Antonio
  • 71,651
  • 11
  • 148
  • 165