使用子类在 Swift 中实现 NSCopying

Implementing NSCopying in Swift with subclasses

考虑两个 classes。第一个是 Vehicle,一个符合 NSCopying:

NSObject subclass
class Vehicle : NSObject, NSCopying {

    var wheels = 4

    func copyWithZone(zone: NSZone) -> AnyObject {
        let vehicle = self.dynamicType()
        vehicle.wheels = self.wheels
        return vehicle
    }
}

第二个class,Starship,继承自Vehicle

class Starship : Vehicle {

    var photonTorpedos = 6
    var antiGravity = true

    override func copyWithZone(zone: NSZone) -> AnyObject {
        let starship = super.copyWithZone(zone) as Starship

        starship.photonTorpedos = self.photonTorpedos
        starship.antiGravity = self.antiGravity
        return starship
    }
}

此代码无法编译,因为:

Constructing an object of class type 'Vehicle' with a metatype value must use a 'required' initializer.

所以我继续添加所需的初始化程序:

required override init () {
    super.init()
}

现在应用程序编译,Starship 对象正确响应 copy()

两个问题:

  1. 为什么用元类型构造对象需要 required 初始化器? (看起来我写的初始化程序什么也没做。)
  2. 是不是我写错了什么,或者应该添加到初始化器中?有没有我没有考虑的情况?

您需要一个 required 初始化器,因为 Swift 中所需初始化器的子类实现需要它。

根据 Swift 关于 Required nitializers 的文档:

You must also write the required modifier before every subclass implementation of a required initializer, to indicate that the initializer requirement applies to further subclasses in the chain.

简答

您不能在不将 init() 标记为 required 的情况下使用 self.dynamicType(),因为无法保证 Vehicle 的子类也将实现 init().

探索问题

看一下The Swift Programming Language: Initialization,上面提到了如何

subclasses do not inherit their superclass initializers by default

子类继承其超类的初始化器的情况是:

Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:

Rule 1

If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.

Rule 2

If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initialisers.

看例子:

class MySuperclass {
    let num = 0

    // MySuperclass is given `init()` as its default initialiser
    // because I gave `num` a default value.
}

class MySubclass : MySuperclass {
    let otherNum: Int

    init(otherNum: Int) {
        self.otherNum = otherNum
    }
}  

根据上面的信息,由于MySubclass定义了没有初始值的属性otherNum,它不会自动从[=20=继承init() ].

现在假设我想将以下方法添加到 MySuperclass:

func myMethod() {
    println(self.dynamicType().num)
}

你会得到你描述的错误,因为不能保证 MySuperclass 的子类会实现 init()(在这个例子中他们不会)。

要解决此问题,您需要将 init() 标记为 required,以确保 MySuperclass 的所有子类实现 init(),因此调用 self.dynamicType() 是一件有效的事情。这与您的问题中的问题相同:Swift 知道 Vehicle 实现 init(),但是它不知道任何子类将实现 init(),因此您需要将其 required

另一个不适合您的示例的解决方案是将 Vehicle 标记为 final,这意味着 Vehicle 不能被子类化。然后你就可以使用 self.dynamicType();但在这种情况下,您也可以只使用 Vehicle()