用子类在Swift中实现NSCopying

Aar*_*ger 12 introspection swift

考虑两个班级.第一个是符合以下条件VehicleNSObject子类NSCopying:

class Vehicle : NSObject, NSCopying {

    var wheels = 4

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

第二类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
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码无法编译,因为:

构造具有元类型值的类型"Vehicle"的对象必须使用"必需的"初始化程序.

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

required override init () {
    super.init()
}
Run Code Online (Sandbox Code Playgroud)

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

两个问题:

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

ABa*_*ith 12

简答

你不能在self.dynamicType()没有标记的情况下使用init(),required因为不能保证子类Vehicle也会实现init().

探索问题

看看Swift编程语言:初始化,它提到了如何

默认情况下,子类不会继承其超类初始值设定项

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

假设您为在子类中引入的任何新属性提供默认值,则适用以下两个规则:

规则1

如果您的子类没有定义任何指定的初始值设定项,它会自动继承其所有超类指定的初始值设定项.

规则2

如果您的子类提供了所有超类指定初始化程序的实现 - 通过按照规则1继承它们,或者通过提供自定义实现作为其定义的一部分 - 那么它会自动继承所有超类便捷初始化程序.

看看这个例子:

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
    }
}  
Run Code Online (Sandbox Code Playgroud)

根据上述信息,因为MySubclass所定义的属性otherNum没有初始值,它不会自动继承init()来自MySuperclass.

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

func myMethod() {
    println(self.dynamicType().num)
}
Run Code Online (Sandbox Code Playgroud)

您将得到您描述的错误,因为无法保证子类MySuperclass将实现init()(在此示例中它们不会).

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

另一种解决方案,在您的示例中不适用,标记Vehiclefinal,意思是Vehicle不能进行子类化.那你就可以用了self.dynamicType(); 但你可能只是Vehicle()在那种情况下使用.