Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Generics with Protocol.Type

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?

like image 969
beal Avatar asked Jan 05 '17 15:01

beal


People also ask

How do I create a generic protocol?

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.

What is generic protocol?

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 a protocol associated type in Swift?

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.

Can a struct conform to a protocol?

Classes, structs and enums can conform to multiple protocols and the conformance relationship can be established retroactively.


1 Answers

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.

like image 104
Vatsal Manot Avatar answered Sep 22 '22 13:09

Vatsal Manot