Реализация 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() правильно.

два вопроса:

  1. почему для построения объекта с метатипом требуется required инициализатор? (Похоже, инициализатор, который я написал, ничего не делает.)
  2. есть ли что-нибудь, что я написал неправильно, или должны добавить в инициализатор? Есть дело, которое я не рассматриваю?

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:

вы также должны написать необходимый модификатор перед каждым подклассом реализация необходимого инициализатора, чтобы указать, что требование инициализатора применяется к дальнейшим подклассам в цепочке.