如何快速从字符串生成初始化调用 [英] How can I generate an init call from strings in swift

查看:83
本文介绍了如何快速从字符串生成初始化调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆