在Swift中使用子类实现NSCopying [英] Implementing NSCopying in Swift with subclasses

查看:529
本文介绍了在Swift中使用子类实现NSCopying的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Consider two classes. The first is Vehicle, an NSObject subclass that conforms to NSCopying:

class Vehicle : NSObject, NSCopying {

    var wheels = 4

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

第二个类StarshipVehicle继承:

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

由于以下原因,该代码无法编译

This code doesn't compile because:

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

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

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

So I go ahead and add a required initializer:

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

现在应用程序将进行编译,并且Starship对象可以正确响应copy().

And now the app compiles, and Starship objects respond to copy() properly.

两个问题:

  1. 为什么构造具有元类型的对象需要required初始化程序? (看来我写的初始化程序什么也没做.)
  2. 我写错了什么吗?还是应该添加到初始化程序?有没有我不考虑的情况?
  1. Why does constructing an object with a metatype need a required initializer? (It appears the initializer I wrote does nothing.)
  2. Is there anything I wrote incorrectly, or should add to the initializer? Is there a case I'm not considering?

推荐答案

简短答案

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

The Short Answer

You cannot use self.dynamicType() without marking init() as required because there's no guarantee subclasses of Vehicle will also implement init().

查看

Taking a look at The Swift Programming Language: Initialization, it's mentioned how

子类默认情况下不继承其超类初始化程序

subclasses do not inherit their superclass initializers by default

子类继承其父类的初始化程序的情况是:

The situations in which a subclass will inherit its superclass' initialisers are:

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

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

规则1

如果您的子类未定义任何指定的初始值设定项,则它 自动继承其所有超类指定的初始化程序.

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

规则2

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

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而没有初始值,因此它不会自动从MySuperclass继承init().

According to the information above, since MySubclass defined the property otherNum without an initial value, it doesn't automatically inherit init() from MySuperclass.

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

Now suppose I want to add the following method to MySuperclass:

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

您将得到您所描述的错误,因为没有保证MySuperclass的子类将实现init()(在本示例中,它们没有实现).

You'll get the error you described because there is no guarantee subclasses of MySuperclass will implement init() (and in this example they don't).

要解决此问题,因此需要将init()标记为required,以确保MySuperclass的所有子类都实现init(),因此调用self.dynamicType()是正确的做法.问题与您的问题相同:Swift知道Vehicle实现init(),但是它不知道任何子类将实现init(),因此您需要将其设置为required.

To solve this problem you therefore need to mark init() as required, to ensure all subclasses of MySuperclass implement init(), and so calling self.dynamicType() is a valid thing to do. It's the same problem as in your question: Swift knows Vehicle implements init(), however it doesn't know any subclasses will implement init() and so you need to make it required.

一个不适合您的示例的替代解决方案是将Vehicle标记为final,这意味着不能对Vehicle进行子类化.这样您就可以使用self.dynamicType()了;但您最好还是在这种情况下使用Vehicle().

An alternative solution, which isn't suitable in your example, is to mark Vehicle as final, meaning Vehicle can't be subclassed. Then you'll be able to use self.dynamicType(); but you might as well just use Vehicle() in that case.

这篇关于在Swift中使用子类实现NSCopying的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆