用子类在Swift中实现NSCopying

时间:2015-01-26 03:36:35

标签: swift introspection

考虑两个班级。第一个是VehicleNSObject子类符合NSCopying

class Vehicle : NSObject, NSCopying {

    var wheels = 4

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

第二课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
    }
}

此代码无法编译,因为:

  

使用元类型值构造类型为“Vehicle”的对象必须使用“必需”初始值设定项。

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

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

现在应用程序已编译,Starship个对象正确回复copy()

两个问题:

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

2 个答案:

答案 0 :(得分:12)

简答

如果没有将self.dynamicType()标记为init(),则无法使用required,因为无法保证Vehicle的子类也会实现init()

探索问题

看看 The Swift Programming Language: Initialization ,它提到了如何

  

子类默认不继承其超类初始值设定项

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

  

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

     

规则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
    }
}  

根据上述信息,由于MySubclass定义了属性otherNum而没有初始值,因此它不会自动从init()继承MySuperclass

现在假设我想将以下方法添加到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()

答案 1 :(得分:0)

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

Required nitializers上的每个Swift文档:

  

您还必须在每个子类之前编写必需的修饰符   执行一个必需的初始化程序,以表示该   初始化程序要求适用于链中的其他子类。