-1

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.

mm24
  • 9,280
  • 12
  • 75
  • 170
  • You can do this via a protocol or a base class. – Cristik Jan 04 '17 at 16:19
  • I wanted to avoid using a base class, however via protocol sounds interesting. Do you have an example? – mm24 Jan 04 '17 at 16:20
  • 1
    Could you please give us a concrete example of what you're looking for? If you want to talk about a finite set of types that don't necessarily share common functionality, an `enum` is probably what you're after. – Hamish Jan 04 '17 at 16:31
  • Possible duplicate of [Generic dictionary value type in Swift](http://stackoverflow.com/questions/24736612/generic-dictionary-value-type-in-swift) – Hamish Jan 04 '17 at 16:46

2 Answers2

3

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.

Cristik
  • 30,989
  • 25
  • 91
  • 127
1

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)")
        }
    }
Josh Homann
  • 15,933
  • 3
  • 30
  • 33