使用字符串值动态 select 自定义 class 并实例化

Dynamically select a custom class using a string value and instantiate

我计划使用字符串值 select 自定义 class。使用 Bundle.main.classNamed.

返回所需的 class 对象

为了更好地理解我想要做什么,这里有一个带有一些自定义 classes 的简短代码示例:

class Product: NSObject {
  var name: String

  init(_ name: String) {
    self.name = name
  }
}

class Apple: Product {
  var num: Int

  init(_ num: Int) {
    self.num = num
    super .init("Apple")
  }
}

class Melon: Product {
  var num: Int
  var size: Int

  init(_ num: Int, _ size: Int) {
    self.num = num
    self.size = size
    super .init("Melon")
  }
}

class AppleMelonProduct 的子class,每个都有自己的初始化方法。给定一个像 "1000 Apples" 这样的字符串值,我想实例化一个 Apple class。为了获得所需的 class 我使用 Bundle.main.classNamed 像这样:

let clsName: String = "Apple"

let nameSpace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
let loadedClass = Bundle.main.classNamed(nameSpace + "." + "Apple") as! NSObject.Type

如何实例化 loadedClass

let apple = loadedClass.init(100)

给出一个Fatal error: Use of unimplemented initializer 'init()' for class 'MyApp.Apple'

let unknownFruit = loadedClass(100)

给出错误:Initializing from a metatype value must reference 'init' explicitly

虽然有两个 subclasses 有两种不同的初始化方法,但应该可以使用 loadedClass 和它自己的 init 方法,但这目前还行不通.


Swift 5.2.4 Xcode11.5

查看我在问题下的评论以获得此答案的上下文。但是我想知道你是不是在解决一个错误的问题,你最好换一个不同的设计。例如,在不知道您的产品 类 是如何使用的情况下,我认为枚举可能是一个很好的案例:

enum Product {

    case apple(num: Int)
    case melon(num: Int, size: Int)

    init?(_ name: String, _ num: Int = 0, _ size: Int = 0) {
        switch name.lowercased() {
        case "apple":
            self = .apple(num: num)
        case "melon":
            self = .melon(num: num, size: size)
        default:
            return nil
        }
    }
}

extension Product: CustomStringConvertible {
    var description: String {
        switch self {
        case .apple(let num):
            return "apple(\(num))"
        case .melon(let num, let size):
            return "melon(\(num) - \(size)"
        }
    }
}

let clsName: String = "Apple"
let apple = Product(clsName, 100)
print("I am \(apple?.description)") // apple(100)

总之,这篇比较耐人寻味,评论太长了!随意删除。