如何快速从字符串生成初始化调用 [英] How can I generate an init call from strings in swift
问题描述
class A {
let val : Int
init(val: Int) {
self.val = val
}
}
我有以下3个字符串:
let className = "A"
let argName = "val"
let argValue = "4"
如何使用这3个字符串调用A(val:4)
?
How can I call A(val:4)
from using these 3 strings?
推荐答案
由于您已经在注释中指出类型都将是某些超类型的子类,因此该超类型可以处理所有调度.在可可中,这是一种非常常见的模式,称为类集群.
Since you've noted in the comments that the types will all be subclasses of some supertype, then that supertype can handle all the dispatching. In Cocoa, this is a pretty common pattern known as a class cluster.
class SuperA {
enum SuperAError: Error {
case cannotConstruct
}
static func create(className: String, argName: String, argValue: String) throws -> SuperA {
switch className {
case "A":
guard argName == "val",
let value = Int(argValue)
else { throw SuperAError.cannotConstruct }
return A(val: value)
default:
throw SuperAError.cannotConstruct
}
}
}
现在,我不太喜欢这种方法.这种子类化往往较差的Swift.当您需要引用类型时,Swift可以很好地使用类,但是它不支持子类化.我会使用Buildable协议和Builder:
Now, I don't particularly like this approach. This kind of subclassing tends to be poor Swift. Swift is fine with classes when you require a reference type, but it doesn't favor subclassing. I'd do this with a Buildable protocol and a Builder:
enum BuildableError: Error {
case unknownType
case badParameters
}
protocol Buildable {
init(argName: String, argValue: String) throws
// ... and the rest of the methods you require ...
}
struct A {
var val: Int
}
extension A: Buildable {
init(argName: String, argValue: String) throws {
guard argName == "val", let value = Int(argValue) else {
throw BuildableError.badParameters
}
self.init(val: value)
}
}
final class Builder {
var buildables: [String: Buildable.Type] = [:]
func build(className: String, argName: String, argValue: String) throws -> Buildable {
guard let buildable = buildables[className] else {
throw BuildableError.unknownType
}
return try buildable.init(argName: argName, argValue: argValue)
}
}
let builder = Builder()
builder.buildables["A"] = A.self
builder.build(className: "A", argName: "val", argValue: "4")
如果这导致代码重复,则有直接的方法可以使用其他协议来解决该问题.例如,如果您的许多类型都具有init(val: Int)
,则它们可以与另一协议共享代码:
If this leads to duplicated code, there are straightforward ways to address that with other protocols. For example, if many of your types had init(val: Int)
, they could share code with another protocol:
protocol ValIntBuildable: Buildable {
init(val: Int)
}
extension ValIntBuildable {
init(argName: String, argValue: String) throws {
guard argName == "val", let value = Int(argValue) else {
throw BuildableError.badParameters
}
self.init(val: value)
}
}
extension A: ValIntBuildable {}
这篇关于如何快速从字符串生成初始化调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!