Я стараюсь помещать только необходимые (сохраненные свойства, инициализаторы) в определения моих классов и перемещать все остальное в свои собственные extension
, вроде как отдельный extension
логический блок, с которым я бы тоже сгруппировал // MARK:
.
Например, для подкласса UIView я бы получил расширение для вещей, связанных с макетом, одно для подписки и обработки событий и так далее. В этих расширениях мне неизбежно придется переопределить некоторые методы UIKit, например layoutSubviews
. Я никогда не замечал никаких проблем с этим подходом - до сегодняшнего дня.
Возьмем, к примеру, эту иерархию классов:
public class C: NSObject {
public func method() { print("C") }
}
public class B: C {
}
extension B {
override public func method() { print("B") }
}
public class A: B {
}
extension A {
override public func method() { print("A") }
}
(A() as A).method()
(A() as B).method()
(A() as C).method()
Выход есть A B C
. Для меня это не имеет смысла. Я читал о статической отправке расширений протокола, но это не протокол. Это обычный класс, и я ожидаю, что вызовы методов будут динамически отправляться во время выполнения. Очевидно, что вызов C
должен по крайней мере динамически отправляться и производиться C
?
Если я удаляю наследование NSObject
и создаю C
корневой класс, компилятор жалуется, говоря declarations in extensions cannot override yet
, о чем я уже читал. Но как наличие NSObject
корневого класса меняет ситуацию?
Перемещение обоих переопределений в их объявление класса дает A A A
ожидаемые результаты, перемещение только B
производит A B B
, перемещение только A
производит C B C
, последнее из которых не имеет для меня абсолютно никакого смысла: даже тот, который статически типизирован для A
создания A
-output, больше не имеет!
Добавление dynamic
ключевого слова к определению или переопределению, кажется, дает мне желаемое поведение «с этой точки в иерархии классов вниз» ...
Давайте изменим наш пример на что-то менее сконструированное, что на самом деле заставило меня опубликовать этот вопрос:
public class B: UIView {
}
extension B {
override public func layoutSubviews() { print("B") }
}
public class A: B {
}
extension A {
override public func layoutSubviews() { print("A") }
}
(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()
Теперь получаем A B A
. Здесь я никак не могу сделать макет UIView динамическим.
Перемещение как переопределение в их объявлении класса возвращает нас A A A
снова, только либо только B по - прежнему получает нас A B A
. dynamic
снова решает мои проблемы.
Теоретически я мог бы добавить dynamic
ко всему, override
что делаю, но чувствую, что делаю здесь что-то еще не так.
Неужели неправильно использовать extension
s для группировки кода, как я?