Требуется ли вызывать реализацию суперкласса для каждой функции каждого подкласса? - PullRequest
0 голосов
/ 01 апреля 2019

например. у вас есть определенный подкласс, который переопределяет функцию f в своем суперклассе. Внутри переопределения вы должны вызывать функцию f суперкласса.

Ответы [ 3 ]

1 голос
/ 22 апреля 2019

Ответ на этот вопрос не имеет отношения к Swift, но относится ко всем языкам ООП.

Простой ответ: нет, вы не обязаны вызывать реализацию суперкласса.

В документации следует указать, следует ли вам вызывать реализацию суперкласса или нет. Когда вы не уверены, вы обычно должны вызывать супер реализацию.

Вы должны учитывать тот факт, что суперкласс делает что-то внутри метода, и если вы не вызываете реализацию суперкласса, подкласс не должен работать должным образом.

Не вызов реализации суперкласса означает, что вы хотите предотвратить реализацию суперкласса, и это обычно означает, что вся ваша модель наследования имеет недостатки.

Одним заметным исключением является ситуация, когда суперкласс предоставляет некоторую реализацию по умолчанию, которую вы хотите заменить внутри своего подкласса (например, UIViewController.loadView). Это не очень распространенный вариант использования.

Есть и другие очевидные исключения, например, геттеры. Когда вы переопределяете метод получения, чтобы вернуть пользовательский объект, обычно нет необходимости вызывать super. Однако, опять же, даже получатели могут технически инициализировать некоторые структуры в суперклассе, и может потребоваться вызвать super.

1 голос
/ 22 апреля 2019

По умолчанию вы вызываете super, , если не знаете, что не нарушаете эту функцию.


Я создал гист .Вы можете скопировать его на свою игровую площадку и поиграть с ним.Но ответ таков:

У меня было именно ваше замешательство.Вы в основном спрашиваете, в чем разница между расширением поведения и переопределением поведения.

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

Предположим, у нас есть следующий класс:

class Person {

    var age : Int?

    func incrementAge() {
        guard age != nil else {
            age = 1
            return
        }
        age! += 1
    }

    func eat() {
        print("eat popcorn")
    }
}

Мы можем просто инициализировать его и сделать:

var p1 = Person()
p1.incrementAge() // works fine

Теперь предположим, что мы сделали это:

class Boy : Person{

    override func incrementAge() {
        age! += 2
    }
}

var b1 = Boy()
b1.incrementAge()

Как вы думаете, что произойдет?!

Это даст сбой. Потому что в суперклассе мы делаем проверку nil для age, но в нашем подклассемы никогда не звоним super

Чтобы это заработало, мы должны позвонить super.

class GoodBoy : Person{

    override func incrementAge() {
        super.incrementAge()
        age! += 2
    }
}

var b2 = GoodBoy()
b2.incrementAge() // works fine. 

Мы могли бы уйти, не вызывая super напрямую.

class AlternateGoodBoy : Person{

    override func incrementAge() {
        guard age != nil else {
            age = 1
            return
        }
        age! += 2
    }
}

var b3 = AlternateGoodBoy()
b3.incrementAge() // works fine.

^^ Вышеописанное работает, но реализация суперкласса нам не всегда известна.Реальный пример - UIKit.Мы не знаем, что происходит на самом деле, когда вызывается viewDidLoad.Следовательно, мы должны позвонить super.viewDidLoad


При этом иногда говорят, что мы можем просто не звонить super и быть в полном порядке, потому что мы знаем, что делает супер или, возможно, просто не заботимся и хотим полностью получитьИзбавься от этого.Например:

class Girl : Person{
    override func eat() {
        print("eat hotdog")
    }
}

var g1 = Girl()
g1.eat() // doesn't crash, even though you overrode the behavior. It doesn't crash because the call to super ISN'T critical

Тем не менее, наиболее распространенным случаем является то, что вы звоните super, но также добавляете что-то поверх него.

class Dad : Person {
    var moneyInBank = 0
    override func incrementAge() {
        super.incrementAge()
        addMoneyToRetirementFunds()
    }

    func addMoneyToRetirementFunds() {
        moneyInBank += 2000
    }
}

var d1 = Dad()
d1.incrementAge()
print(d1.moneyInBank) // 2000

Pro tip:

В отличие от большинства переопределений, когда вы сначала вызываете super, а затем остальные, для функции tearDown лучшедля вызова super.tearDown() в конце функции.В общем, для любых «удаленных» функций вы должны вызывать super в конце.например, viewWillDisAppear / viewDidDisappear

1 голос
/ 01 апреля 2019

Ответ ложный, вам не нужно вызывать метод суперкласса, который вы переопределяете в Swift или в ООП в целом. Это было бы ужасным ограничением, если бы вы сделали! Бывают случаи, когда вам на самом деле не следует вызывать его, и, возможно, наиболее распространенный пример - это когда вы создаете UIViewController программно и должны переопределить loadView() без вызова super.loadView().

...