Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Swift Dictionary subclass?

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.

like image 567
Heath Borders Avatar asked Feb 23 '15 19:02

Heath Borders


People also ask

How is a dictionary different from an array in Swift?

Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations. Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store.

Which syntax is correct for declare dictionary in Swift?

Which syntax is correct for declare dictionary in Swift? To declare a dictionary you can use the square brackets syntax( [KeyType:ValueType] ). You can initialize a dictionary with a dictionary literal. A dictionary literal is a list of key-value pairs, separated by commas, surrounded by a pair of square brackets.

How dictionary works internally Swift?

dictionary in Swift is used to store elements. Dictionary also contains one key while storing elements to it, later on, we can use these keys to access the elements store in the dictionary. Dictionary in swift does not maintain the insertion order of the element in which they are stored, they are unordered in nature.


3 Answers

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.

like image 107
promacuser Avatar answered Sep 19 '22 18:09

promacuser


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.

like image 8
Catfish_Man Avatar answered Oct 17 '22 08:10

Catfish_Man


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
}
like image 6
user3763801 Avatar answered Oct 17 '22 08:10

user3763801