在Swift中使用子类实现NSCopying [英] Implementing NSCopying in Swift with subclasses
问题描述
考虑两个类.第一个是Vehicle
,它是符合NSCopying
的NSObject
子类:
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
}
}
第二个类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
}
}
由于以下原因,该代码无法编译
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.
两个问题:
- 为什么构造具有元类型的对象需要
required
初始化程序? (看来我写的初始化程序什么也没做.) - 我写错了什么吗?还是应该添加到初始化程序?有没有我不考虑的情况?
- Why does constructing an object with a metatype need a
required
initializer? (It appears the initializer I wrote does nothing.) - 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屋!