koen
koen

Reputation: 5729

Generic dictionary in Swift

I have several structs Foo, Bar, Baz, and I use the function below to read a plist into a [String : Foo] dictionary. And I have a method that creates a [String : Bar] dictionary, etc. This all works well.

func loadFoo() -> [String : Foo]? {
    guard
       let path = Bundle.main.path(forResource: "foo", ofType: "plist"),
       let plistDict = NSDictionary(contentsOfFile: path) as? [String : AnyObject]
       else { return nil }

    var dict = [String : Foo]()

    for (key, f) in plistDict {
       if let info = f as? [String : AnyObject] {
           let foo = Foo(symbol: key, info: info)
           dict[key] = foo
        }
    }

    return dict
} 

Of course, this screams "use generics", but I have not yet been able to get it to work. For instance, I replaced Foo with <A> or A, but get a bunch of compiler errors (I am away from my Mac right now, so cannot reproduce the errors here).

Any suggestions how to tackle this?

Upvotes: 3

Views: 7198

Answers (1)

vadian
vadian

Reputation: 285079

  • Create a protocol that all common structs must conform to by implementing the init method init(symbol:info:)

    protocol Fooable {
      init(symbol: String, info: [String : AnyObject])
    }
    
  • Make all your structs adopt that protocol

    struct Baz : Fooable { ...
    
  • Now you can make the load method generic by constraining the type to Fooable

    func loadFoo<T:Fooable>() -> [String : T]? {
      guard
        let path = Bundle.main.path(forResource: "foo", ofType: "plist"),
        let plistDict = NSDictionary(contentsOfFile: path) as? [String : AnyObject]
        else { return nil }
    
      var dict = [String : T]()
    
      for (key, f) in plistDict {
        if let info = f as? [String : AnyObject] {
          let foo = T(symbol: key, info: info)
          dict[key] = foo
        }
      }
    
      return dict
    }
    
  • and call it with

    let bazObject : [String : Baz]? = loadFoo()
    

    This syntax to annotate the type passes Baz as the generic parameter.

Upvotes: 3

Related Questions