我试图拥有一个通用的 Plugin
类,然后是诸如 PluginOne
和 PluginTwo
之类的子类,它们可以通过添加函数 run()
和 output
属性,以便每个插件可以执行自定义命令并保存输出。
类似这样的事情:
class Plugin: Decodable {
var name: String
init(name: String) {
self.name = name
}
}
class PluginOne: Plugin {
var output: String?
init(name: String, output: String) {
self.output = output
super.init(name: name)
}
func run() {
// do something
self.output = "Some output"
}
}
class PluginTwo: Plugin {
var output: String?
init(name: String, output: String) {
self.output = output
super.init(name: name)
}
func run() {
// do something
self.output = "Some other output"
}
}
现在我从 json 中获取可用插件的列表:
let json = """
[
{ "type": "PluginOne", "name": "First plugin of type one" },
{ "type": "PluginOne", "name": "Second plugin of type one" },
{ "type": "PluginTwo", "name": "abcd" }
]
"""
我正在将文件解码为[Plugin]
:
let decoder = JSONDecoder()
let jsonData = Data(json.utf8)
let plugins = try decoder.decode([Plugin].self, from: jsonData)
现在的问题是如何从每个 Plugin
正确创建子类 PluginOne
和 PluginTwo
以便 run()
他们每个人?
此外,我知道我做错了什么,也许应该立即解码为子类(如何?)和/或使用协议(protocol)而不是子类。
请指教
执行第一个答案的结果:
import Foundation
let json = """
[
{ "type": "PluginOne", "name": "First plugin of type one" },
{ "type": "PluginOne", "name": "Second plugin of type one" },
{ "type": "PluginTwo", "name": "abcd" }
]
"""
class Plugin: Decodable {
var name: String
init(name: String) {
self.name = name
}
}
class PluginOne: Plugin {
var output: String?
init(name: String, output: String) {
self.output = output
super.init(name: name)
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
func run() {
// do something
self.output = "Some output"
}
}
class PluginTwo: Plugin {
var output: String?
init(name: String, output: String) {
self.output = output
super.init(name: name)
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
func run() {
// do something
self.output = "Some other output"
}
}
let decoder = JSONDecoder()
let jsonData = Data(json.utf8)
let plugins = try decoder.decode([Plugin].self, from: jsonData)
for plugin in plugins {
if let pluginOne = plugin as? PluginOne {
pluginOne.run()
print(pluginOne.output ?? "empty one")
}
else if let pluginTwo = plugin as? PluginTwo {
pluginTwo.run()
print(pluginTwo.output ?? "empty two")
} else {
print("error")
}
}
// Result: error error error
最佳答案
对于“如何正确使用子类”这个问题的回答通常是“不要”。 Swift 提供了不同的范例:我们采用 WWDC 2016 视频 Protocol and Value Oriented Programming in UIKit Apps 中概述的面向协议(protocol)编程,而不是面向对象编程。 .
protocol Plugin: Decodable {
var name: String { get }
func run()
}
struct PluginOne: Plugin {
let name: String
func run() { ... }
}
struct PluginTwo: Plugin {
let name: String
func run() { ... }
}
接下来的问题是“如何解析 JSON”,我们将采用 Encoding and Decoding Custom Types 的“手动编码和解码”部分中概述的技术。文档:
struct Plugins: Decodable {
let plugins: [Plugin]
init(from decoder: Decoder) throws {
enum AdditionalInfoKeys: String, CodingKey {
case type
case name
}
var plugins: [Plugin] = []
var array = try decoder.unkeyedContainer()
while !array.isAtEnd {
let container = try array.nestedContainer(keyedBy: AdditionalInfoKeys.self)
let type = try container.decode(PluginType.self, forKey: .type)
let name = try container.decode(String.self, forKey: .name)
switch type {
case .pluginOne: plugins.append(PluginOne(name: name))
case .pluginTwo: plugins.append(PluginTwo(name: name))
}
}
self.plugins = plugins
}
}
与
enum PluginType: String, Decodable {
case pluginOne = "PluginOne"
case pluginTwo = "PluginTwo"
}
然后您可以执行以下操作:
do {
let plugins = try JSONDecoder().decode(Plugins.self, from: data)
print(plugins.plugins)
} catch {
print(error)
}
这将为您提供符合 Plugin
协议(protocol)的对象数组。
关于swift - 如何在 Swift 5 中正确使用子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58245399/