这个层次结构应该如何运作?

时间:2019-04-23 16:58:04

标签: swift generics polymorphism

我正在为一个学校项目制作框架,并且我决定将泛型用作每个UIView的基准。我尝试将这些“实体”添加到通用字典中,该字典将采用“实体”类型。我尝试添加到此列表的类名为“ EntityPlay”,并且是“ Entity”的子类。我尝试将此类添加到“字典”中,但是出现编译错误,指示“ EntityPlay”和“ Entity”不兼容。

我绘制了实体的层次结构,并得出结论说“实体”实际上只是一个“实体”并没有什么错。

public class View {
    private var map : [Entity<UIView>]
    private func addEntity<T : Entity<UIView>>(_ entity : T) -> Void {
        self.map.append(entity)
    }
}

public class Entity<T : UIView> {
    some code
}

public class SomeClass {
    public func someFunc() -> Void {
        view.addEntity(EntityPlay())
    }
}
public class EntityPlay : Entity<UIImageView> {
    some code
}

根据上述逻辑,我希望这段代码可以完全正常工作,但是会导致编译错误,指示“ EntityPlay”与“ Entity”无关。

3 个答案:

答案 0 :(得分:0)

我认为,如果只对UIView进行子类化以创建Entity类,那么您会更好地构建类的层次结构。您是否需要使用泛型的特定原因?

我对发生的事情的猜测是,您已经定义了一个只能包含一个Entity的字典-当您尝试向其添加EntityPlay类时,它是一个imageView,这会导致此问题。如果您的字典被明确定义为可以接受[Any:Any],那么您可能可以解决此问题-但您必须解开包装中出现的所有结果,因为它们都是可选的。不用说,这将是一场噩梦。

答案 1 :(得分:0)

{ "type": "shell", "inline": "mkdir /var/apps" }, EntityPlay是不兼容的类型。设置泛型的类型时,您可以想象这是一个全新的类定义。

答案 2 :(得分:0)

侧栏注释:如果您打算从其类的外部调用addEntity,则不能将其声明为private

问题:

调用view.addEntity(EntityPlay())时出错的原因是:

addEntity方法采用类型Entity<UIView>的参数,它不是EntityPlay类型的 ;换句话说,即使您将Entity<UIView>Entity<UIImageView>视为“但UIImageView基本上是UIView!”,但在处理泛型时就不是这种情况。 / p>

解决方案:

您可能需要创建一个抽象层来声明包含异构类型的集合。作为一种好习惯,您可以创建一个新协议,从而声明协议类型的map数组。示例:

protocol EntityProtocol {
    func doSomething()
}

public class View {
    private var map : [EntityProtocol] = []
    func addEntity<T : EntityProtocol>(_ entity : T) -> Void {
        self.map.append(entity)
    }
}

此时,您需要使Entity符合EntityProtocol;因此,由于EntityPlay是从Entity继承的,因此它也隐式符合EntityProtocol

public class Entity<T : UIView>: EntityProtocol {
    func doSomething() {
        print("Entity!!")
    }
}

public class EntityPlay : Entity<UIImageView> {
    override func doSomething() {
        print("EntityPlay!!!")
    }
}

输出:

要检查输出,让我们调用addEntity两次,并向其传递EntityEntityPlay实例:

public class SomeClass {
    public func someFunc() -> Void {
        let view = View()
        // Entity
        let entityView = Entity()
        view.addEntity(entityView)

        // EntityPlay
        let entityPlay = EntityPlay()
        view.addEntity(entityPlay)

        // let's assume that `map` is public:
        for e in view.map {
            e.doSomething()
        }
    }
}

let test = SomeClass()
test.someFunc()
// Entity!!
//EntityPlay!!!