【问题标题】:Implementing NSCopying in Swift with subclasses使用子类在 Swift 中实现 NSCopying
【发布时间】:2015-03-24 12:47:10
【问题描述】:

考虑两个类。第一个是Vehicle,一个符合NSCopyingNSObject子类:

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. 我写错了什么,或者应该添加到初始化程序中吗?有没有我没有考虑的案例?

【问题讨论】:

    标签: swift introspection


    【解决方案1】:

    简短回答

    您不能在不将init() 标记为required 的情况下使用self.dynamicType(),因为不能保证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没有初始值,它不会自动从MySuperclass继承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()

    【讨论】:

    • 很好的答案,尤其是在使用NSCopying 时。有关在 Swift 中复制的更多讨论(没有 NSCopying),您可能还对 stackoverflow.com/questions/25645090/… 感兴趣。
    • 感谢您的撰写。同意:很好的答案。
    • 很好的答案!这应该是 Swift 编程语言
    【解决方案2】:

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

    Required nitializers 上的每个 Swift 文档:

    您还必须在每个子类之前编写 required 修饰符 实现所需的初始化程序,以指示 初始化器要求适用于链中的其他子类。

    【讨论】:

    • 其实它似乎工作正常,即使我删除super.init()
    • 是的,因为您覆盖了它。我应该说它基本上需要一个初始化器,因为它不一定会从它的超类继承它......
    • 这对我来说没有意义...... all 方法不是继承自超类吗?你能说更多吗?有没有可以引用的文档?
    猜你喜欢
    • 2011-05-27
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 2011-05-04
    • 2010-12-30
    • 1970-01-01
    相关资源
    最近更新 更多