Абстрактные classы в языке Swift

Есть ли способ создать абстрактный class на языке Swift, или это ограничение, как Objective-C? Я хотел бы создать абстрактный class, сопоставимый с тем, что Java определяет как абстрактный class.

    В Swift нет абстрактных classов (как Objective-C). Лучше всего использовать протокол , который похож на интерфейс Java.

    С помощью Swift 2.0 вы можете добавить реализации методов и вычисленные реализации свойств с использованием расширений протокола. Ваши единственные ограничения заключаются в том, что вы не можете предоставить переменные-члены или константы, и динамическая отправка отсутствует .

    Примером этого метода может быть:

    protocol Employee { var annualSalary: Int {get} } extension Employee { var biweeklySalary: Int { return self.annualSalary / 26 } func logSalary() { print("$\(self.annualSalary) per year or $\(self.biweeklySalary) biweekly") } } struct SoftwareEngineer: Employee { var annualSalary: Int func logSalary() { print("overridden") } } let sarah = SoftwareEngineer(annualSalary: 100000) sarah.logSalary() // prints: overridden (sarah as Employee).logSalary() // prints: $100000 per year or $3846 biweekly 

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

    Также обратите внимание, что каждый class или структура, реализующая протокол Employee, должен будет снова объявить свойство annualSalary.

    Самое главное, обратите внимание, что динамическая отправка отсутствует . Когда logSalary вызывается в экземпляре, который хранится как SoftwareEngineer он вызывает переопределенную версию метода. Когда logSalary вызывается в экземпляре после того, как он был logSalary Employee , он вызывает исходную реализацию (она не динамически не отправляет в переопределенную версию, даже если экземпляр на самом деле является Software Engineer .

    Для получения дополнительной информации проверьте видео WWDC об этой функции: Создание лучших приложений со значениями типов в Swift

    Обратите внимание, что этот ответ ориентирован на Swift 2.0 и выше

    Вы можете добиться такого же поведения с протоколами и расширениями протоколов.

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

     protocol Drivable { var speed: Float { get set } } 

    Затем вы можете добавить поведение по умолчанию ко всем типам, которые соответствуют ему

     extension Drivable { func accelerate(by: Float) { speed += by } } 

    Теперь вы можете создавать новые типы, внедряя Drivable .

     struct Car: Drivable { var speed: Float = 0.0 init() {} } let c = Car() c.accelerate(10) 

    Итак, в основном вы получаете:

    1. Скомпилируйте проверки времени, которые гарантируют, что все Drivable
    2. Вы можете реализовать поведение по умолчанию для всех типов, которые соответствуют Drivable ( accelerate )
    3. Drivable гарантированно не Drivable поскольку это всего лишь протокол

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

    Я думаю, что это самое близкое к abstract Java или рефералу C #:

     class AbstractClass { private init() { } } 

    Обратите внимание, что для того, чтобы private модификаторы работали, вы должны определить этот class в отдельном файле Swift.

    EDIT: Тем не менее, этот код не позволяет объявить абстрактный метод и тем самым принудительно его реализовать.

    После того, как я боролся несколько недель, я наконец понял, как перевести абстрактный class Java / PHP в Swift:

     public class AbstractClass: NSObject { internal override init(){} public func getFoodToEat()->String { if(self._iAmHungry()) { return self._myFavoriteFood(); }else{ return ""; } } private func _myFavoriteFood()->String { return "Sandwich"; } internal func _iAmHungry()->Bool { fatalError(__FUNCTION__ + "Must be overridden"); return false; } } public class ConcreteClass: AbstractClass, IConcreteClass { private var _hungry: Bool = false; public override init() { super.init(); } public func starve()->Void { self._hungry = true; } public override func _iAmHungry()->Bool { return self._hungry; } } public protocol IConcreteClass { func _iAmHungry()->Bool; } class ConcreteClassTest: XCTestCase { func testExample() { var concreteClass: ConcreteClass = ConcreteClass(); XCTAssertEqual("", concreteClass.getFoodToEat()); concreteClass.starve(); XCTAssertEqual("Sandwich", concreteClass.getFoodToEat()); } } 

    Однако я думаю, что Apple не реализовывала абстрактные classы, потому что вместо этого вместо этого используется шаблон delegate + protocol. Например, такой же шаблон выше был бы лучше выполнен следующим образом:

     import UIKit public class GoldenSpoonChild { private var delegate: IStomach!; internal init(){} internal func setup(delegate: IStomach) { self.delegate = delegate; } public func getFoodToEat()->String { if(self.delegate.iAmHungry()) { return self._myFavoriteFood(); }else{ return ""; } } private func _myFavoriteFood()->String { return "Sandwich"; } } public class Mother: GoldenSpoonChild, IStomach { private var _hungry: Bool = false; public override init() { super.init(); super.setup(self); } public func makeFamilyHungry()->Void { self._hungry = true; } public func iAmHungry()->Bool { return self._hungry; } } protocol IStomach { func iAmHungry()->Bool; } class DelegateTest: XCTestCase { func testGetFood() { var concreteClass: Mother = Mother(); XCTAssertEqual("", concreteClass.getFoodToEat()); concreteClass.makeFamilyHungry(); XCTAssertEqual("Sandwich", concreteClass.getFoodToEat()); } } 

    Мне нужен такой шаблон, потому что я хотел бы распространять некоторые методы в UITableViewController, такие как viewWillAppear и т. Д. Было ли это полезно?

    Самый простой способ – использовать вызов fatalError("Not Implemented") в абстрактный метод (не переменный) в расширении протокола.

     protocol MyInterface { func myMethod() -> String } extension MyInterface { func myMethod() -> String { fatalError("Not Implemented") } } class MyConcreteClass: MyInterface { func myMethod() -> String { return "The output" } } MyConcreteClass().myMethod() 

    Существует способ моделирования абстрактных classов с использованием протоколов. Это пример:

     protocol MyProtocol { func doIt() } class BaseClass { var myDelegate: MyProtocol! init() { ... } func myFunc() { ... self.myDelegate.doIt() ... } } class ChildClass: BaseClass, MyProtocol { override init(){ super.init() self.myDelegate = self } func doIt() { // Custom implementation } } 

    Еще один способ, которым можно реализовать абстрактный class, – заблокировать инициализатор. Я сделал это так:

     class Element:CALayer { // IT'S ABSTRACT CLASS override init(){ super.init() if self.dynamicType === Element.self { fatalError("Element is abstract class, do not try to create instance of this class") } } } 

    Я пытался создать class абстрактной Weather , но использование протоколов было не идеальным, так как мне приходилось писать одни и те же методы init снова и снова. Расширение протокола и запись метода init имели свои проблемы, тем более, что я использовал NSObject соответствующий NSCoding .

    Поэтому я придумал это для соответствия NSCoding :

     required init?(coder aDecoder: NSCoder) { guard type(of: self) != Weather.self else { fatalError(" This is an abstract class. Use a subclass of `Weather`.") } // Initialize... } 

    Что касается init :

     fileprivate init(param: Any...) { // Initialize } 

    Переместите все ссылки на абстрактные свойства и методы базового classа на реализацию расширения протокола, где Self ограничивается базовым classом. Вы получите доступ ко всем методам и свойствам базового classа. Кроме того, компилятор проверяет реализацию абстрактных методов и свойств в протоколе для производных classов

     protocol Commom:class{ var tableView:UITableView {get}; func update(); } class Base{ var total:Int = 0; } extension Common where Self:Base{ func update(){ total += 1; tableView.reloadData(); } } class Derived:Base,Common{ var tableView:UITableView{ return owner.tableView; } } 
    Interesting Posts

    В браузере Google Chrome, почему Gmail использует большую часть процессора при включении аппаратного ускорения?

    Maven: добавьте зависимость к банке относительным путем

    Как обрабатывать изменение флажка с помощью jQuery?

    Как преобразовать DbSet в инфраструктуру Entity в ObjectQuery

    Spring MVC – Как вернуть простую строку в JSON в Rest Controller

    Шифрование zip действительно плохо?

    Конвертировать PDF 2 стороны на страницу до 1 стороны на страницу

    Hibernate: как переопределить атрибут из сопоставленного суперclassа

    В чем разница между строковой константой и строковым литералом?

    Как перемещать столбцы с перетаскиванием в Excel 2011?

    Можем ли мы сделать unsigned byte в Java?

    Не удалось войти в систему. Проверьте подключение к сети и повторите попытку.

    Условное двоичное соединение и обновление по ссылке с использованием пакета data.table

    Как проверить, является ли диск Win 7 64-разрядным и какая версия?

    Песочница против вредоносного кода в приложении Java

    Давайте будем гением компьютера.