Swift:在协议扩展的静态var中存储Protocol的实现类型

时间:2017-05-20 01:16:17

标签: ios swift macos protocols extension-methods

好的,我有这个协议MenuEntry,我想用它来填充TableView:

protocol MenuEntry {
    static var title: String { get }
    static func entrySelected(_ menuController: MenuController)
}

我想在不同的地方实现这个协议,让项目本身决定做什么。它可能是一个实现协议的UIViewController或一个简单的结构,然后在菜单本身上调用一个函数:

struct SomeEntry: MenuEntry {
    static var title: String { return "Some Entry" }
    static func entrySelected(_ menuController: MenuController) {
        menuController.doSomething()
    }
}

现在我想构建MenuControllers数据源,但没有实际实例化条目,因为当填充MenuControllers数据源时,特别是我的视图控制器不一定可用。这就是我在MenuEntry中使用静态var / func的原因。目前,我可以简单地填充数据源:

let dataSource: [MenuEntry.Type] = [SomeEntry.self]

它看起来效果很好。我可以获取条目并调用相应的函数:

dataSource.first?.title   //Gives me "Some Entry"

现在是棘手的部分。我以为我可以非常聪明并创建一个协议扩展,我在其中引用我实现协议的所有类型,如下所示:

extension MenuEntry {
    static var someEntry: MenuEntry.Type { return SomeEntry.self }
    //...
}

然后通过MenuEntry.someEntry使用它们。但是,在MenuEntry上访问someEntry会给我一个错误:

error: static member 'someEntry' cannot be used on protocol metatype 'MenuEntry.Protocol'

所以我的问题是:我错过了什么?我只是试图以一种无意的方式滥用语言,或者我只是做错了什么?

从下面接受的答案来看,我现在是怎么做的。首先,我们需要提到的结构(我不需要一个类):

struct MenuEntries {}

然后,无论我在哪里实现MenuEntry协议,我还扩展了这个结构并添加了这样的条目:

struct SomeEntry: MenuEntry {
    static var title: String { return "Some Entry" }
    static func entrySelected(_ menuController: MenuController) {
        menuController.doSomething()
    }
}

extension MenuEntries {
    static var someEntry: MenuEntry.Type { return SomeEntry.self }
}

最后一件事就是创建我的数据源:

let dataSource: [MenuEntry.Type] = [MenuEntries.someEntry, ...]

好的,现在我在一个地方有一个所有菜单条目的列表。缺点是我必须记住每次都扩展MenuEntries。除了有一些神奇的方法来扩展条件库上的结构我不知道。但我猜这只是顶部,根本不可能。

1 个答案:

答案 0 :(得分:0)

来自The Swift Book

  

协议定义了适合特定任务或功能的方法,属性和其他要求的蓝图。然后,可以通过类,结构或枚举采用来提供这些要求的实际实现。“

您的扩展程序正在尝试直接在协议中实现功能,但这是不允许的;只有采用该协议的类,结构或枚举才能提供功能。

您可以定义一个返回菜单类的类:

class MenuFactory {
    static var someEntry: MenuEntry.type { return SomeEntry.self }
}