I have a problem with generics in Swift (3):
I get different data of different classes, implementing the same protocol, from server and I need to put them into a class with generics (e.g. Array).
I do not know which class the data will be so I need to use the protocol. So I have following structure:
My protocol:
protocol MyProtocol {
// some protocol stuff
}
Some classes implementing the protocol
class MyProtocolImpl1: MyProtocol{
// some class stuff
}
class MyProtocolImpl2: MyProtocol {
// some class stuff
}
....
class with generic:
final class MyGenericsClass<T: MyProtocol> {
// some class stuff
}
now I want to use this class this way:
func createClass<T>(model: T.Type) -> MyGenericClass<T> {
let myClass = MyGenericClass<T>()
return myClass
}
...
EDIT
func getClass() -> MyProtocol.Type {
return MyProtocolImpl1.self
}
let impl1 = getClass()
let impl2 = MyProtocolImpl2.self
let createdClass = createClass(impl1) //not working
let createdClass = createClass(impl2) //working
doing createClass(impl1)
I get this error:
cannot invoke 'createClass' with an argument list of type '(MyProtocol.Type)'
Changing the MyProtocol to a class would fix the problem but then I could not be sure every class inheriting from it implements the needed methods.
Does someone have some ideas how to solve this problem?
There are two ways to create a generic protocol - either by defining an abstract associatedtype or the use of Self (with a capital S). The use of Self or associatedtype is what we like to call "associated types". This is because they are only associated with the protocol they are defined in.
Generic Protocols are for procedures/techniques involving human participants that are used on a regular basis, and which form all or part of subsequent research projects or taught modules.
What is an associated type? An associated type can be seen as a replacement of a specific type within a protocol definition. In other words: it's a placeholder name of a type to use until the protocol is adopted and the exact type is specified. This is best explained by a simple code example.
Classes, structs and enums can conform to multiple protocols and the conformance relationship can be established retroactively.
The answer is that you can't do this. MyProtocol.self
is not a concrete type, ergo it cannot conform to MyProtocol
. You cannot pass MyProtocol
when your function expects a concrete type T
, following T: MyProtocol
.
Think about it this way; if I were to add a static function, doFoo()
to MyProtocol
, and you initialized GenericClass<MyProtocol>
and decided to call MyProtocol.doFoo()
inside some method, what function would it call? It doesn't make any sense, because MyProtocol
is not a concrete type (i.e. a class, struct or enum), it's a protocol.
A note on your comment:
The problem is that I do not know if it is ClassA or ClassB or ClassX. I just know that it is a subclass of MyProtocol
This is where you are erring. "subclass of MyProtocol" does not make sense, because MyProtocol
is not a class.
How about this? You end up with AnyObject
, but you can cast it to MyGenericClass<T>
later when you do know T
.
extension MyProtocol
{
static func createMyGenericClass() -> AnyObject
{
return MyGenericClass<Self>()
}
}
func createClass(_ modelType: MyProtocol.Type) -> AnyObject
{
return modelType.createMyGenericClass()
}
You could also make MyGenericClass
inherit from some base class, and have that store a variable for MyProtocol.Type
. That way, you could use specific functions from your MyProtocol
conformee type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With