Я хотел бы создать абстрактную функцию на быстром языке. Является ли это возможным?
class BaseClass {
func abstractFunction() {
// How do I force this function to be overridden?
}
}
class SubClass : BaseClass {
override func abstractFunction() {
// Override
}
}
Ответы:
В Swift нет концепции абстрактного (например, Objective-C), но вы можете сделать это:
источник
assert(false, "This method must be overriden by the subclass")
.fatalError("This method must be overridden")
preconditionFailure("Bla bla bla")
Swift, который будет выполняться в сборках релизов, а также устраняет необходимость в операторе возврата. EDIT: Только что узнал , что этот метод в основном равно ,fatalError()
но это более правильный способ (лучшая документация, представленная в Swift вместе сprecondition()
,assert()
иassertionFailure()
, читайте здесь )Вам нужен не базовый класс, а протокол.
Если вы не предоставляете abstractFunction в своем классе, это ошибка.
Если вам все еще нужен базовый класс для другого поведения, вы можете сделать это:
источник
Я переношу изрядное количество кода с платформы, которая поддерживает абстрактные базовые классы, на Swift и часто использую его. Если то, что вы действительно хотите, - это функциональность абстрактного базового класса, то это означает, что этот класс служит как реализацией функциональности общего класса (в противном случае это был бы просто интерфейс / протокол), И он определяет методы, которые должны быть реализованы производные классы.
Для этого в Swift вам понадобится протокол и базовый класс.
Обратите внимание, что базовый класс реализует общие методы, но не реализует протокол (поскольку он не реализует все методы).
Затем в производном классе:
Производный класс наследует sharedFunction от базового класса, помогая ему удовлетворить эту часть протокола, и протокол по-прежнему требует, чтобы производный класс реализовал abstractFunction.
Единственный реальный недостаток этого метода заключается в том, что, поскольку базовый класс не реализует протокол, если у вас есть метод базового класса, которому требуется доступ к свойству / методу протокола, вам придется переопределить его в производном классе и оттуда вызвать передача базового класса (через super),
self
чтобы у базового класса был экземпляр протокола, с которым он мог бы выполнять свою работу.Например, допустим, что sharedFunction необходимо вызвать abstractFunction. Протокол останется прежним, а классы теперь будут выглядеть так:
Теперь sharedFunction из производного класса удовлетворяет эту часть протокола, но производный класс по-прежнему может совместно использовать логику базового класса достаточно простым способом.
источник
Похоже, это «официальный» способ, которым Apple обрабатывает абстрактные методы в UIKit. Взгляните на
1. Поместите абстрактный метод в протокол 2. Напишите свой базовый класс 3. Напишите подкласс (ы). Вот как все это использоватьUITableViewController
то, как он работаетUITableViewDelegate
. Одна из самых первых вещей , которые вы делаете, чтобы добавить строку:delegate = self
. Что ж, в этом и весь фокус.Проверьте с Playground, чтобы увидеть результат.
Некоторые замечания
UITableViewController
реализует,UITableViewDelegate
но по-прежнему должен быть зарегистрирован как делегат, явно установивdelegate
свойство.источник
getComments
метод родительского делегата. Есть несколько типов комментариев, и мне нужны те, которые относятся к каждому объекту. Итак, я хочу, чтобы подклассы не компилировались, когда я это делаю,delegate.getComments()
если я не отменяю этот метод. VC просто знает, что у него естьParentDelegate
вызываемый объектdelegate
, илиBaseClassX
в вашем примере, ноBaseClassX
не имеет абстрактного метода. Мне нужен VC, чтобы точно знать, что он используетSubclassedDelegate
.Один из способов сделать это - использовать необязательное замыкание, определенное в базовом классе, и дочерние элементы могут выбирать, реализовывать его или нет.
источник
Что ж, я знаю, что опаздываю в игру и, возможно, использую произошедшие изменения. Извини за это.
В любом случае, я хотел бы внести свой ответ, потому что мне нравится проводить тестирование, и решения с
fatalError()
, AFAIK, не тестируются, а те, которые имеют исключения, намного сложнее тестировать.Я бы посоветовал использовать более быстрый подход. Ваша цель - определить абстракцию, которая имеет некоторые общие детали, но не полностью определена, то есть абстрактный метод (ы). Используйте протокол, который определяет все ожидаемые методы в абстракции, как те, которые определены, так и те, которые не определены. Затем создайте расширение протокола, реализующее методы, определенные в вашем случае. Наконец, любой производный класс должен реализовывать протокол, что означает все методы, но те, которые являются частью расширения протокола, уже имеют свою реализацию.
Расширение вашего примера одной конкретной функцией:
Обратите внимание, что, делая это, компилятор снова становится вашим другом. Если метод не «переопределен», вы получите ошибку во время компиляции вместо тех, которые вы бы получили,
fatalError()
или исключений, которые произошли бы во время выполнения.источник
Я понимаю, что вы сейчас делаете, думаю, вам лучше воспользоваться протоколом
Затем вы просто соответствуете протоколу:
Если ваш класс также является подклассом, протоколы следуют за суперклассом:
источник
Использование
assert
ключевого слова для принудительного применения абстрактных методов:Однако, как сказал Стив Ваддикор, вы, вероятно, захотите
protocol
взамен.источник
Я понимаю вопрос и искал такое же решение. Протоколы - это не то же самое, что абстрактные методы.
В протоколе вам необходимо указать, что ваш класс соответствует такому протоколу, абстрактный метод означает, что вы должны переопределить такой метод.
Другими словами, протоколы являются своего рода необязательными, вам нужно указать базовый класс и протокол, если вы не укажете протокол, вам не нужно переопределять такие методы.
Абстрактный метод означает, что вам нужен базовый класс, но вам необходимо реализовать свой собственный метод или два, что не одно и то же.
Мне нужно такое же поведение, поэтому я искал решение. Думаю, в Swift такой функции нет.
источник
Есть еще одна альтернатива этой проблеме, хотя есть и обратная сторона по сравнению с предложением @ jaumard; для этого требуется оператор возврата. Хотя я упускаю из виду необходимость этого, потому что он заключается в непосредственной выдаче исключения:
А потом:
Все, что будет после этого, недостижимо, поэтому я не понимаю, зачем форсировать возврат.
источник
AbstractMethodException().raise()
?Не знаю, будет ли это полезно, но у меня была аналогичная проблема с абстрактным методом при попытке создать игру SpritKit. Мне нужен был абстрактный класс Animal с такими методами, как move (), run () и т.д., но имена спрайтов (и другие функции) должны предоставляться дочерними элементами класса. В итоге я сделал что-то вроде этого (проверено на Swift 2):
источник