/ / Deklaracje z rozszerzeń nie mogą być jeszcze nadpisane w Swift 4 - ios, metody-rozszerzeń, swift4

Deklaracji z rozszerzeń nie można jeszcze przesłonić w Swift 4 - ios, extensions-methods, swift4

Niedawno przeprowadziłem migrację kodu do Swift 4. Jest problem, z którym mam do czynienia rozszerzenia, tj

Deklaracje z rozszerzeń nie mogą być jeszcze nadpisane

Przeczytałem już wiele postów dotyczących tego wydania. Ale żaden z nich nie bawi się w scenariuszu opisanym poniżej:

class BaseCell: UITableViewCell
{
//Some code here...
}

extension BaseCell
{
func isValid() -> String?
{
//Some code here...
}
}

class SampleCell: BaseCell
{
//Some code here...

override func isValid() -> String? //ERROR..!!!
{
//Some code here...
}
}

Według Apple

Rozszerzenia mogą dodawać nowe funkcje do typu, ale nie mogą zastępować istniejących funkcji.

Ale w powyższym scenariuszu nie zastępuję metody isValid() w rozszerzeniu. Jest zastępowany w SampleCell sama definicja klasy. Mimo to daje błąd.

Odpowiedzi:

5 dla odpowiedzi № 1

Ale w powyższym scenariuszu nie zastępuję metody isValid() w przedłużeniu.

isValid zostanie zadeklarowany w pliku rozbudowa.

Błąd prawie mówi, że jeśli funkcja jest zadeklarowana w ten sposób, nie można tego zmienić.

Oświadczenie jest ważne dla obu z rozszerzenia i w rozszerzeniu.


2 dla odpowiedzi nr 2

Myślę, że to jest oczywiste. deklaracje OD rozszerzeń nie można jeszcze nadpisać

Próbujesz override funkcja func isValid() -> String? który został zadeklarowany w ramach extension z BaseCell, nie the BaseCell sama klasa.

To wyraźnie mówi, że nie można przesłonić czegoś, co zostało zadeklarowane w rozszerzeniu.

Mam nadzieję, że to jest pomocne.


2 dla odpowiedzi nr 3

W Swift 3 mogłeś przesłonić funkcję rozszerzenia, jeśli rozszerzenie należało do klasy, która jest wyprowadzana z Objective-C (http://blog.flaviocaetano.com/post/this-is-how-to-override-extension-methods/), ale wydaje mi się, że teraz nie jest to możliwe w Swift 4. Możesz oczywiście zrobić coś takiego:

protocol Validity {
func isValid() -> String?
}

class BaseCell: UITableViewCell, Validity {

}

extension Validity
{
func isValid() -> String? {
return "false"
}
}

class SampleCell: BaseCell {

func isValid() -> String? {
return "true"
}
}


let base = BaseCell()
base.isValid() // prints false

let sample = SampleCell()
sample.isValid() // prints true

0 dla odpowiedzi nr 4

Jest nieważne w Swift, ale nie w Objective-C. Tak więc, jeśli Twoja sygnatura metody na to pozwala (brak zakazanych konstrukcji objc), możesz to zadeklarować @objc func myMethod() i zastąpić go swobodnie w Swift.


0 dla odpowiedzi № 5

Ja też miałem ogromną spuściznę kodu Swift 3, który był używanyta stara sztuczka, aby osiągnąć to, co chciałem, więc kiedy przeniosłem się na Swift 4 i zacząłem otrzymywać te błędy, byłem nieco zdenerwowany. Nie bój się, jest rozwiązanie.

Ten błąd ma związek ze sposobem, w jaki Swift 4kompiluje klasy i nowy sposób, w jaki traktuje klasy i funkcje Objective-C. W Swift 3, jeśli klasa pochodzi z NSObject, wówczas wszystkie zmienne i funkcje w tej klasie używałyby konwencji dynamicznego nazewnictwa i wyszukiwania Objective-C. Takie podejście uniemożliwiło Swiftowi optymalizację kodu i poprawę wydajności kodu oraz rozmiar.

Aby przezwyciężyć te kary, w Swift 4 tylko zmienne i funkcje są wyraźnie oznaczone tagiem @objc dostać traktowanie Objective-C, wszystko inne używa standardowych konwencji Swift: stąd błąd.

Uzbrojony w tę wiedzę, rozwiązaniem problemu jest oznaczenie funkcji w rozszerzeniu, które chcesz zastąpić @objc, następnie w klasach potomnych zastąp funkcję, ale pamiętaj o dołączeniu rozszerzenia @objc tag, aby Twój kod był wywoływany w czasie wykonywania.

OSTRZEŻENIE Jest tu trochę haczyka: jeśli zapomnisz dołączyć rozszerzenie @objc w override, kompilator nie będzie narzekał, ale w Twoim kodzie brakuje dynamicznego wyszukiwania, więc nigdy nie jest wywoływany w czasie wykonywania.

Twój kod powinien więc wyglądać mniej więcej tak:

class BaseCell: UITableViewCell {
//Some code here...
}

extension BaseCell {
@objc func isValid() -> String? {
//Some code here...
}
}

class SampleCell: BaseCell {
//Some code here...

@objc override func isValid() -> String? {
//Some code here...
}
}