如何从具有共同基类的类中创建实例?

huangapple go评论63阅读模式
英文:

How to create an instance from classes that have a common base class?

问题

以前我用Objective-C编写了一个方法,像这样:

Class className = classMap[nameKey];
return [[className alloc] init];

现在我需要一个Swift版本。我有这样的字典:

private var classMap = [String: BaseClass.Type]()
classMap[name1] = SomeClass1.self
classMap[name2] = SomeClass2.self
...

所有的 "SomeClass" 都是 BaseClass 的子类。这是我想要使用它的方式:

func createInstance(from name: String) -> BaseClass? {
    guard let className = classMap[name] else {
        return nil
    }
    let model = className.init()
    return model
}

然后我得到了一个错误:

用元类型值构造类类型 'BaseClass' 的对象必须使用 'required' 初始化程序

英文:

Previously I wrote a method in Objective-C like this:

Class className = classMap[nameKey];
return [[className alloc] init];

Now I need a swift version. I have a dictionary like this:

private var classMap = [String: BaseClass.Type]()
classMap[name1] = SomeClass1.self
classMap[name2] = SomeClass2.self
...

All the "SomeClass" are subclasses of BaseClass. And this is how I want to use it:

func createInstance(from name: String) -> BaseClass? {
    guard let className = modelMap[name] else {
        return nil
    }
    let model = modelClass.init()
    return model
}

Then I got an error:

>Constructing an object of class type 'BaseClass' with a metatype value must use a 'required' initializer

答案1

得分: 2

通过添加'required'关键字解决:

required override init()

有更好的解决方案吗?@matt只是说工厂方法会更好。这是否意味着我应该编写类似以下内容:

if name == "type_1"
    return Class1()
else if name == "type_2"
    return Class2()
else if ...
英文:

Solved by just adding a 'required' keyword:

required override init()

Is there any better solution? @matt just said a factory method would be better. Does that mean I should write something like:

if name == "type_1"
    return Class1()
else if name == "type_2"
    return Class2()
else if ...

答案2

得分: 2

我建议的是编写一个返回 Self 的工厂方法。考虑这个模型:

class Dog {
    required init() {
    }
    class func make() -> Self { // *
        return Self()
    }
}
class NoisyDog : Dog {
}

现在,Dog.make() 创建一个 Dog,类型为 Dog,而 NoisyDog.make() 创建一个 NoisyDog,类型为 NoisyDog。这种方法的好处是返回的实例会自动正确地具有正确的类型,如果这个类有需要初始化的属性,你还可以添加参数和属性初始化。

此外,我还想重申我在评论中提到的一点:不要传递元类型。你的整个代码中的

classMap[name1] = SomeClass1.self

与 Swift 的精神相悖。你可以传递 函数引用(我经常这样做),甚至整个 匿名函数,只需使用字典选择要调用的函数,然后直接调用它;但听起来你可能遇到了某些问题,仍然试图以 Objective-C 的方式解决它,尽管你现在正在使用 Swift,这是不正确的。

英文:

What I'm suggesting is that you write a factory method that returns Self. Consider this model:

class Dog {
    required init() {
    }
    class func make() -> Self { // *
        return Self()
    }
}
class NoisyDog : Dog {
}

Now Dog.make() makes a Dog, typed as a Dog, and NoisyDog.make() makes a NoisyDog, typed as a NoisyDog. The nice things about this approach are that the returned instances are automatically typed correctly, and that you can add parameters and property initializations if this thing has properties that need initializing.

Also, though, I'd like to repeat what I said in a comment: Don't pass metatypes around. Your entire

classMap[name1] = SomeClass1.self

is repugnant to the spirit of Swift. You can pass function references around (and I do that absolutely all the time), or even entire anonymous functions, where you just use the dictionary to pick the one to call and simply call it; but it sounds to me like you've got some problem and you're still trying to solve it in the Objective-C way even though you're now using Swift, and that's wrong.

huangapple
  • 本文由 发表于 2023年3月9日 20:41:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684767.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定