Реализация NSCopying в Swift с подклассами
рассмотрим два занятия. Первый -Vehicle
, an 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
}
}
этот код не компилируется, потому что:
построение объекта типа класса "транспортное средство" со значением метатипа должно использовать инициализатор "required".
поэтому я продолжаю и добавляю необходимый инициализатор:
required override init () {
super.init()
}
и теперь приложение компилируется, и Starship
объекты отвечают на copy()
правильно.
два вопроса:
- почему для построения объекта с метатипом требуется
required
инициализатор? (Похоже, инициализатор, который я написал, ничего не делает.) - есть ли что-нибудь, что я написал неправильно, или должны добавить в инициализатор? Есть дело, которое я не рассматриваю?
2 ответов
Короткий Ответ:
вы не можете использовать self.dynamicType()
без маркировки init()
as required
потому что нет никаких гарантий подклассов Vehicle
также будет осуществлять init()
.
Изучение Проблемы
посмотреть Язык Программирования Swift: Инициализация, упоминается как
подклассы не наследуют свои инициализаторы суперклассов по умолчанию
ситуации, в которых подкласс будет наследовать initialisers его суперкласса являются:
предполагая, что вы предоставляете значения по умолчанию для любых новых свойств введите в подкласс следующие два правила:
Правило 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()
as required
, для обеспечения всех подклассов MySuperclass
реализовать init()
, и поэтому вызов self.dynamicType()
это действительная вещь. Это та же проблема, что и в вашем вопросе: Swift знает Vehicle
осуществляет init()
, однако он не знает, что все подклассы реализуют init()
и так вам нужно сделать это required
.
альтернативным решением, которое не подходит в вашем примере, является пометка Vehicle
as final
, что означает Vehicle
не может быть разделен на подклассы. Тогда вы сможете использовать self.dynamicType()
; но вы также можете просто использовать Vehicle()
in это дело.
вам понадобится required
инициализатор, потому что для реализации подкласса требуется инициализатор в Swift.
в документации Swift на требуются nitializers:
вы также должны написать необходимый модификатор перед каждым подклассом реализация необходимого инициализатора, чтобы указать, что требование инициализатора применяется к дальнейшим подклассам в цепочке.