ios - Swift:将协议(protocol)的实现类型存储在协议(protocol)扩展的静态变量中

标签 ios swift macos protocols extension-methods

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

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

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

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

现在我想构建 MenuControllers 数据源,但没有实际实例化条目,因为尤其是在填充 MenuControllers 数据源时,我的 View Controller 不一定可用。这就是为什么我在 MenuEntry 中使用 static var/func 的原因。目前,我可以简单地执行此操作来填充数据源:

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

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

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

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

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 协议(protocol),我都会扩展此结构并添加条目,如下所示:

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。除了我不知道有一些神奇的方法可以在条件基础上扩展结构。但我想这太过分了,根本不可能。

最佳答案

来自The Swift Book

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.”

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

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

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

关于ios - Swift:将协议(protocol)的实现类型存储在协议(protocol)扩展的静态变量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44080955/

相关文章:

macos - 在 NSTabView 上加载同一 NSViewController 的不同实例

macos - 在终端中生成随机文本文件

ios - UICollectionViewCell 中圆形 UIImageView 的错误

ios - Swift 5 - 使用 Alamofire 上传 MultipartFormData 和图库中的图像

ios - 奇怪的核心数据行为(重复条目)

swift - 尝试调用 convenience init, Swift 时调用中的额外参数

android - 是否可以通过无线网络将我的项目部署到 Smartface 模拟器?

ios - 如何增加整个应用程序的字体大小?

Ios 10 iPhone 7 键盘在收到通知时消失

macos - 核心数据软管本身