好的,我想出了如何得到我需要的东西。
如您所知,问题是我需要限制 RawRepresentable 的类型,这需要泛型/关联类型,但如果使用它,则无法将变量定义为该类型的数组。
但后来我问自己为什么需要那个。答案是因为我正在使用 RawRepresentable:String 来构建另一个 CommandDefinition 对象集合,这是我真正感兴趣的值。因此,解决方案是使用具有该第二级的第二级协议关联类型以满足不能拥有它们的第一级(基本)协议的要求。
这是上面的重写,添加了拼图的缺失部分。
首先,可以按原样添加到任何扩展项目的可重用框架。它由 CommandSetBase、CommandSet、ExtensionBase 和 CommandSet 上的扩展组成:
typealias CommandDefinition = [XCSourceEditorCommandDefinitionKey: Any]
protocol CommandSetBase : XCSourceEditorCommand {
static var commandDefinitions : [CommandDefinition] { get }
}
protocol CommandSet : CommandSetBase {
associatedtype Command : RawRepresentable where Command.RawValue == String
static var commands:[Command] { get }
}
class ExtensionBase : NSObject, XCSourceEditorExtension {
var commandSets:[CommandSetBase.Type]{
return []
}
final var commandDefinitions: [CommandDefinition] {
return commandSets.flatMap{ commandSet in commandSet.commandDefinitions }
}
}
这是 CommandSet 的扩展,它使用 CommandSet 定义的“commands”关联类型来满足 commandDefinitions 的 CommandSetBase 要求(这是缺失的部分):
extension CommandSet {
static var commandDefinitions:[CommandDefinition] {
return commands.map({
command in
return [
XCSourceEditorCommandDefinitionKey.classNameKey : String(reflecting:self),
XCSourceEditorCommandDefinitionKey.identifierKey : String(describing:command),
XCSourceEditorCommandDefinitionKey.nameKey : command.rawValue
]
})
}
}
这是命令集的特定于应用程序的实现以及使用它们的扩展。
首先,扩展本身......
class Extension : ExtensionBase {
override var commandSets:[CommandSetBase.Type]{
return [
NavigationCommands.self,
SelectionCommands.self
]
}
func extensionDidFinishLaunching() {
}
}
现在选择命令:
class SelectionCommands: NSObject, CommandSet {
enum Command : String {
case align = "Align"
case alignWithOptions = "Align with options..."
}
static let commands = [
Command.align,
Command.alignWithOptions
]
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {
print("You executed the Selection command \(invocation.commandIdentifier)")
completionHandler(nil)
}
}
最后,导航命令:
class NavigationCommands : NSObject, CommandSet {
enum Command : String {
case jumpTo = "Jump to..."
case goBack = "Go back"
}
static let commands = [
Command.jumpTo,
Command.goBack
]
func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {
print("You executed the Navigation command \(invocation.commandIdentifier)")
completionHandler(nil)
}
}
这是结果......
如果 Swift 允许您枚举枚举的情况,那么我可以消除上面 CommandSets 中看似多余的“静态 let 命令”。