Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从swift中的字符串生成init调用_Swift_Initialization_Swift5 - Fatal编程技术网

如何从swift中的字符串生成init调用

如何从swift中的字符串生成init调用,swift,initialization,swift5,Swift,Initialization,Swift5,我有以下3个字符串: class A { let val : Int init(val: Int) { self.val = val } } 如何使用这3个字符串调用A(val:4)。Swift不是动态的,您可以基于类的字符串名实例化任意类,等等。Objective-C是动态的,有办法做到这一点,因此,如果这类事情对您很重要,请创建一个NSObject子类,并用Objective-C编写这部分代码(或使用等效的Cocoa/objc运行时调用)。仅在本机Swift中,您不能

我有以下3个字符串:

class A {
  let val : Int
  init(val: Int) {
     self.val = val
  }
}

如何使用这3个字符串调用
A(val:4)
。Swift不是动态的,您可以基于类的字符串名实例化任意类,等等。Objective-C是动态的,有办法做到这一点,因此,如果这类事情对您很重要,请创建一个NSObject子类,并用Objective-C编写这部分代码(或使用等效的Cocoa/objc运行时调用)。

仅在本机Swift中,您不能这样做。Swift不是动态的,您可以基于类的字符串名实例化任意类,等等。Objective-C是动态的,有办法做到这一点,因此如果这类事情对您很重要,那么创建一个NSObject子类,并在Objective-C中编写这部分代码(或者使用等效的Cocoa/objc运行时调用)。

因为您在注释中注意到,这些类型都将是某些超类型的子类,然后,该超类型可以处理所有调度。在Cocoa中,这是一种非常常见的模式,称为类集群

let className = "A"
let argName = "val"
let argValue = "4"
现在,我并不特别喜欢这种方法。这种子类化往往很差。当您需要引用类型时,Swift可以处理类,但它不支持子类化。我会用一个可构建的协议和一个构建器来实现这一点:

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
        }
    }
}
如果这会导致代码重复,那么可以通过其他协议直接解决这一问题。例如,如果您的许多类型具有
init(val:Int)
,则它们可以与其他协议共享代码:

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")

因为您在注释中已经注意到,这些类型都是某些超类型的子类,所以该超类型可以处理所有的分派。在Cocoa中,这是一种非常常见的模式,称为类集群

let className = "A"
let argName = "val"
let argValue = "4"
现在,我并不特别喜欢这种方法。这种子类化往往很差。当您需要引用类型时,Swift可以处理类,但它不支持子类化。我会用一个可构建的协议和一个构建器来实现这一点:

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
        }
    }
}
如果这会导致代码重复,那么可以通过其他协议直接解决这一问题。例如,如果您的许多类型具有
init(val:Int)
,则它们可以与其他协议共享代码:

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")

从字符串获取类的方法是使用NSClassFromString。进行任意方法调用的方法是使用NSInvocation。从字符串获取类的方法是使用NSClassFromString。进行任意方法调用的方法是使用NSInvocation。这是完全任意选择的类和参数,还是定义良好且有限的选择?如果是后者,工厂类可能是一个解决方案。它是后者。工厂类的具体含义是什么?我可以在C++中看到如何做,但是在SWIFT中,我不知道如何去做它。一旦你调用了代码> A(Val:4),接下来你会做什么,因为你对返回的值(比如它的属性)一无所知?没有办法做到你在这里所说的,但是有很多方法可以实现你所暗示的。不过,有意义的解决方案取决于目标。我将在其上执行此操作的所有类(包括A)都来自同一个基类,它提供了我感兴趣的常见功能。这是完全任意选择的类和参数,还是定义良好且有限的选择?如果是后者,工厂类可能是一个解决方案。它是后者。工厂类的具体含义是什么?我可以在C++中看到如何做,但是在SWIFT中,我不知道如何去做它。一旦你调用了代码> A(Val:4),接下来你会做什么,因为你对返回的值(比如它的属性)一无所知?没有办法做到你在这里所说的,但是有很多方法可以实现你所暗示的。不过,有意义的解决方案取决于目标。我将在其上执行此操作的所有类(包括A)都来自同一个基类,它们提供了我感兴趣的常见功能。问题是一些初始值设定项具有多个参数。我甚至不清楚它们是否有相同的类型。查看链接问题(我将其描述为一个“分布式”问题,OP一直在分发部分)。谢谢Rob,你问题的第一部分很好地解决了我的问题。matt提供的信息不正确,只关注负面信息,因此我感谢有人真正关注帮助。问题是一些初始值设定项有多个参数。我甚至不清楚它们是否有相同的类型。查看链接问题(我将其描述为一个“分布式”问题,OP一直在分发部分)。谢谢Rob,你问题的第一部分很好地解决了我的问题。matt提供的信息不正确,只关注负面信息,因此我感谢有人真正关注帮助。