Czy istnieje standardowy sposób tworzenia „czystej funkcji wirtualnej” w języku Swift, tj. taki, który musi być nadpisany przez każdą podklasę, a jeśli tak nie jest, powoduje błąd czasu kompilacji?
swift
abstract
swift-protocols
JuJoDi
źródło
źródło
protocol
s (w porównaniu dointerface
s w Javie) .Jeśli potrzebujesz ich używać jak metod abstrakcyjnych, spójrz na to pytanie / odpowiedź: stackoverflow.com/a/39038828/2435872Odpowiedzi:
Masz dwie możliwości:
1. Użyj protokołu
Zdefiniuj nadklasę jako protokół zamiast klasy
Pro : Sprawdzanie czasu kompilacji, czy każda „podklasa” (a nie rzeczywista podklasa) implementuje wymagane metody
Wada : „Nadklasa” (protokół) nie może implementować metod ani właściwości
2. Assert w super wersji metody
Przykład:
class SuperClass { func someFunc() { fatalError("Must Override") } } class Subclass : SuperClass { override func someFunc() { } }
Pro : Potrafi implementować metody i właściwości w nadklasie
Wada : brak kontroli czasu kompilacji
źródło
fatalError
nie zapewnia sprawdzania czasu kompilacji, fajnie jest, że kompilator jest przynajmniej wystarczająco inteligentny, aby nie wymagać od ciebie dostarczania wartości zwracanej dla metody, gdy wywoływana jest ścieżka wykonaniafatalError
.super.someFunc()
metodę z nadpisaniem, otrzymasz błąd pomimo tego, że go przesłoniłeś. Wiesz, że nie powinieneś tego nazywać, ale ktoś inny nie musi o tym wiedzieć i po prostu postępować zgodnie ze standardową praktyką.Poniższe pozwala na dziedziczenie z klasy, a także na sprawdzenie czasu kompilacji protokołu :)
protocol ViewControllerProtocol { func setupViews() func setupConstraints() } typealias ViewController = ViewControllerClass & ViewControllerProtocol class ViewControllerClass : UIViewController { override func viewDidLoad() { self.setup() } func setup() { guard let controller = self as? ViewController else { return } controller.setupViews() controller.setupConstraints() } //.... and implement methods related to UIViewController at will } class SubClass : ViewController { //-- in case these aren't here... an error will be presented func setupViews() { ... } func setupConstraints() { ... } }
źródło
Nie ma wsparcia dla abstrakcyjnych klas / funkcji wirtualnych, ale prawdopodobnie w większości przypadków możesz użyć protokołu:
protocol SomeProtocol { func someMethod() } class SomeClass: SomeProtocol { func someMethod() {} }
Jeśli SomeClass nie zaimplementuje someMethod, zostanie wyświetlony następujący błąd kompilacji:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
źródło
Innym obejściem, jeśli nie masz zbyt wielu "wirtualnych" metod, jest przekazanie podklasy "implementacji" do konstruktora klasy bazowej jako obiektów funkcji:
class MyVirtual { // 'Implementation' provided by subclass let fooImpl: (() -> String) // Delegates to 'implementation' provided by subclass func foo() -> String { return fooImpl() } init(fooImpl: (() -> String)) { self.fooImpl = fooImpl } } class MyImpl: MyVirtual { // 'Implementation' for super.foo() func myFoo() -> String { return "I am foo" } init() { // pass the 'implementation' to the superclass super.init(myFoo) } }
źródło
Można użyć protokołu vs twierdzeniu, jak zasugerowano w odpowiedzi tutaj przez
drewag
. Brakuje jednak np. Protokołu. Kryję się tutaj,Protokół
protocol SomeProtocol { func someMethod() } class SomeClass: SomeProtocol { func someMethod() {} }
Teraz wszystkie podklasy są wymagane do implementacji protokołu sprawdzanego w czasie kompilacji. Jeśli SomeClass nie zaimplementuje someMethod, zostanie wyświetlony następujący błąd kompilacji:
Uwaga: działa to tylko dla najwyższej klasy, która implementuje protokół. Każda podklasa może beztrosko zignorować wymagania protokołu. - tak skomentował przez
memmons
Twierdzenie
class SuperClass { func someFunc() { fatalError("Must Override") } } class Subclass : SuperClass { override func someFunc() { } }
Jednak asercja będzie działać tylko w czasie wykonywania.
źródło
Będąc nowym w rozwoju iOS, nie jestem do końca pewien, kiedy to zostało zaimplementowane, ale jednym ze sposobów uzyskania najlepszego z obu światów jest zaimplementowanie rozszerzenia dla protokołu:
protocol ThingsToDo { func doThingOne() } extension ThingsToDo { func doThingTwo() { /* Define code here */} } class Person: ThingsToDo { func doThingOne() { // Already defined in extension doThingTwo() // Rest of code } }
To rozszerzenie pozwala ci mieć domyślną wartość dla funkcji, podczas gdy funkcja w zwykłym protokole nadal dostarcza błąd czasu kompilacji, jeśli nie jest zdefiniowany
źródło