问题 用子类在Swift中实现NSCopying


考虑两个类。首先是 Vehicle,一个 NSObject 符合的子类 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. 为什么构造具有元类型的对象需要a required 初始化? (看来我写的初始化程序什么也没做。)
  2. 有没有我写错了,或者 应该 添加到初始化程序?有没有我不考虑的情况?

5633
2018-01-26 03:36


起源



答案:


简答

你不能用 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
    }
}  

根据以上信息,自此 MySubclass 定义了财产 otherNum 没有初始值,它不会自动继承 init() 从 MySuperclass

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

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

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

因此,要解决此问题,需要进行标记 init() 如 required,以确保所有子类 MySuperclass 实行 init()等等 self.dynamicType() 是一件有效的事情。这与问题中的问题相同:斯威夫特知道 Vehicle 器物 init()但是它不知道任何子类将实现 init() 所以你需要做到 required

在您的示例中不适合的替代解决方案是标记 Vehicle 如 final,意思 Vehicle 不能分类。然后你就可以使用了 self.dynamicType();但你可能只是使用 Vehicle() 在这种情况下。


12
2018-05-19 23:45



很好的答案,特别是在使用时 NSCopying。有关在Swift中复制的更多讨论(没有 NSCopying) 您也可能对。。。有兴趣 stackoverflow.com/questions/25645090/...。 - Rob Napier
谢谢你的写作。同意:很好的答案。 - Aaron Brager
很棒的答案!这应该是 Swift编程语言 - fujianjin6471


答案:


简答

你不能用 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
    }
}  

根据以上信息,自此 MySubclass 定义了财产 otherNum 没有初始值,它不会自动继承 init() 从 MySuperclass

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

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

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

因此,要解决此问题,需要进行标记 init() 如 required,以确保所有子类 MySuperclass 实行 init()等等 self.dynamicType() 是一件有效的事情。这与问题中的问题相同:斯威夫特知道 Vehicle 器物 init()但是它不知道任何子类将实现 init() 所以你需要做到 required

在您的示例中不适合的替代解决方案是标记 Vehicle 如 final,意思 Vehicle 不能分类。然后你就可以使用了 self.dynamicType();但你可能只是使用 Vehicle() 在这种情况下。


12
2018-05-19 23:45



很好的答案,特别是在使用时 NSCopying。有关在Swift中复制的更多讨论(没有 NSCopying) 您也可能对。。。有兴趣 stackoverflow.com/questions/25645090/...。 - Rob Napier
谢谢你的写作。同意:很好的答案。 - Aaron Brager
很棒的答案!这应该是 Swift编程语言 - fujianjin6471


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

每个Swift文档 所需的硝化剂

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


0
2018-01-26 03:55



实际上,即使我删除它似乎工作正常 super.init()。 - Aaron Brager
是的,因为你覆盖了它。我应该说它基本上需要一个初始化器,因为它不一定会从它的超级类继承它。 - Tokuriku
这对我来说没有意义......不是 所有 从超类继承的方法?你能谈谈这个吗?你有什么文件可以引用吗? - Aaron Brager