Is it possible to specify the object type allowed in a Dictionary?

142 views Asked by At

In Swift 3.x is it possible to specify the object type allowed in a Dictionary?

It would be great if at declaration time we could pass a set of object types allowed.

2

There are 2 answers

0
Cristik On

You can achieve this via a custom protocol that is implemented only by the types you want to allow within the dictionary:

protocol AllowedDictionaryValue: {}

extension String: AllowedDictionaryValue {}
extension Int: AllowedDictionaryValue {}
extension MyClass: AllowedDictionaryValue {}
extension MyEnum: AllowedDictionaryValue {}

let dictionary: [String:AllowedDictionaryValue] = ...

The above dictionary will hold only String's, Int's, MyClass instances, and MyEnum values.

This way you can have only the values you want in the dictionary, while keeping the dictionary heterogenous.

0
Josh Homann On

You can accomplish this behavior using an enum with associated values, which is called a tagged union in other languages. Its basically a way to have a type that can be restricted to an arbitrary set of types instead of Any or AnyObject. The enum part is the tag that tells you what kind of data you have and the associated value is the actual data for that type. Not that the advantage here to using Any or AnyObject is that the switch statement is exhaustive and the compiler can enforce that you handle all cases at compile time while this is not true if you use Any with a chain of if let statements.

    import PlaygroundSupport
    import UIKit


    enum Number {
        case integer(Int), double(Double), currency(NSDecimalNumber)
    }
    var dictionary: [String : Number] = [ "a" : .integer(1), "b" : .double(2), "c" : .currency(NSDecimalNumber(value: 3))]

    for (key, value) in dictionary {
        switch value {
        case .integer(let number):
            print ("\(key) has a type of \(type(of: number)) with a value of \(number)")
        case .double(let number):
            print ("\(key) has a type of \(type(of: number)) with a value of \(number)")
        case .currency(let number):
            print ("\(key) has a type of \(type(of: number)) with a value of \(number)")
        }
    }