Reputation: 5729
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
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