【问题标题】:Swift Generics with Protocol.Type带有 Protocol.Type 的 Swift 泛型
【发布时间】:2017-01-05 15:12:08
【问题描述】:

我在 Swift (3) 中遇到泛型问题:

我从服务器获得不同类的不同数据,实现相同的协议,我需要将它们放入具有泛型的类(例如数组)中。

我不知道数据是哪个类,所以我需要使用协议。所以我有以下结构:

我的协议:

protocol MyProtocol {
    // some protocol stuff
}

一些实现协议的类

class MyProtocolImpl1: MyProtocol{
    // some class stuff
}

class MyProtocolImpl2: MyProtocol {
    // some class stuff
}
....

泛型类:

final class MyGenericsClass<T: MyProtocol> {
    // some class stuff
}

现在我想这样使用这个类:

func createClass<T>(model: T.Type) -> MyGenericClass<T> {
    let myClass = MyGenericClass<T>()
    return myClass
}

...

编辑

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

createClass(impl1)我得到这个错误:

cannot invoke 'createClass' with an argument list of type '(MyProtocol.Type)'

将 MyProtocol 更改为一个类可以解决问题,但是我不能确定从它继承的每个类都实现了所需的方法。

有人知道如何解决这个问题吗?

【问题讨论】:

  • func createClass&lt;T: MyProtocol&gt; 修复了吗?
  • 您能解决问题吗?
  • 你想将MyProtocol.self 传递给函数,而不是MyProtocol.Type。但即便如此,您也不能拥有MyGenericClass&lt;MyProtocol&gt;,因为MyProtocol 不是符合MyProtocol 的类型——请参阅Protocol doesn't conform to itself?
  • 此链接中的解释非常有帮助。谢谢你。因此,如果 Swift 目前不支持此权利,是否有一些很好的解决方法来解决这个问题?你有什么想法吗?
  • @beal 真的取决于您使用MyGenericClass 的目的。问题的真正症结在于您试图混合通用占位符,这些占位符在编译时与您在运行时获得的类型一起解决。您很可能应该使用非泛型类并使用类型MyProtocol 而不是泛型占位符T。现在您谈论的是符合MyProtocol任何 类型,而不是一种特定类型——因为您不知道直到运行时该类型是什么。

标签: swift generics protocols


【解决方案1】:

答案是您不能这样做。 MyProtocol.self 不是具体类型,因此它不能符合 MyProtocol。当你的函数需要一个具体类型 T 时,你不能传递 MyProtocol,在 T: MyProtocol 之后。

这样想;如果我要添加一个静态函数doFoo()MyProtocol,然后你初始化GenericClass&lt;MyProtocol&gt; 并决定在某个方法中调用MyProtocol.doFoo(),它会调用什么函数?这没有任何意义,因为MyProtocol 不是具体类型(即类、结构或枚举),它是一个协议


关于您的评论的注释:

问题是我不知道是ClassA还是ClassB还是ClassX。我只知道它是 MyProtocol 的子类

这是你犯错的地方。 “MyProtocol 的子类”没有意义,因为 MyProtocol 不是类


这个怎么样?你最终会得到AnyObject,但是当你确实知道T时,你可以将它转换为MyGenericClass&lt;T&gt;

extension MyProtocol
{
    static func createMyGenericClass() -> AnyObject
    {
        return MyGenericClass<Self>()
    }
}

func createClass(_ modelType: MyProtocol.Type) -> AnyObject
{
    return modelType.createMyGenericClass()
}

您也可以让MyGenericClass 从某个基类继承,并让它为MyProtocol.Type 存储一个变量。这样,您可以使用 MyProtocol 符合者类型中的特定功能。

【讨论】:

  • 感谢您的回答。但这并不能解决我的问题。我编辑了问题以使其更清楚。我想将 MyProtocol 的实现传递给createClass() e。 G。 MyProtocolImpl.self
  • 有趣的解决方案,但它们对我不起作用:在您的第一个解决方案中,我无法投射 Any,因为它仅在运行时才知道。您的第二个解决方案不适用于我的情况,因为 MyGenericClass 来自框架
  • @user7302727:所有 Swift 类在内部都是 Objective-C 类。您可以使用关联对象将您的MyProtocol 符合者类型(例如ClassA.selfClassB.self)存储在MyGenericClass 的实例中。
  • 但是要实例化 MyGenericClass(用于设置关联的对象),我需要给它一个特定的类。
  • @user7302727:不,你没有。只需使用我的第一个解决方案,并将其转换为 AnyObject。你甚至不需要强制转换,对我的原始代码进行简单的修改就可以解决问题。
【解决方案2】:

我不完全明白你想要做什么,但我认为这就是你想要的。

import Foundation


protocol MyProtocol {
}

class ClassA : MyProtocol {
}

class ClassB : MyProtocol {
}

final class GenericClass<T:MyProtocol> {

}

func createClass<T:MyProtocol>(_ model: T.Type) -> GenericClass<T> {
    let myClass = GenericClass<T>()
    return myClass
}
let createdClass = createClass(ClassA.self)

【讨论】:

  • 问题是不知道是ClassA还是ClassB还是ClassX。我只知道它是 MyProtocol 的子类
猜你喜欢
  • 2016-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-10
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多