2016-12-05 10 views
6

Mam rozszerzenie klasy zadeklarowane w innym module (używając strąków) w ten sposób.Nie można przesłonić metody otwartej zadeklarowanej w rozszerzeniu klasy w innym module swift

public extension UIView { 
    open func doStuff() {...} 
} 

A kiedy próbują przesłonić tej metody w podklasie wewnątrz mojego obecnego modułu projektu

class ConcreteView : UIView { 
    override open func doStuff() {...} 
} 

pojawia się błąd:

Overriding non-open instance method outside of its defining module

pomimo metody jest właściwie oznaczone jako otwarte

Jako obejście zadeklarowałem inna klasa wewnątrz samego modułu w którym rozszerzenie jest zadeklarowana i overrided pożądany sposób nie

public class CustomView: UIView { 
    override open func doStuff() {...} 
} 

i ustawić tę klasę jako super klasy dla mojej klasy w module głównym

class ConcreteView : CustomView 

tak tylko po to byłem w stanie przesłonić metoda.

To naprawdę wygląda jak błąd w swift3, ale może pominąłem pewne zrozumienie, dlaczego działa w ten sposób?

+2

to wygląda podobnie: http://stackoverflow.com/questions/39141975/swift-open-keyword-overridable-method-properties-in-extension. - Usuń 'public' z' publicznego rozszerzenia UIView'. –

+1

@MartinR yeap, działa - dzięki! Byłoby wspaniale, gdybyś sformułował opis, dlaczego działa w ten sposób w odpowiedzi, abym mógł go oznaczyć lub przynajmniej wytłumaczyć gdzieś w sieci. –

Odpowiedz

9

Krótka odpowiedź:doStuff metoda

public extension UIView { 
    open func doStuff() {...} 
} 

posiada efektywny poziom dostępu „publiczny”, ponieważ rozszerzenie jest oznaczone publicznego. Dlatego nie można go przesłonić w podklasie.

Zauważ, że Xcode ostrzega

warning: declaring instance method in PUBLIC extension

i tekst ostrzegawczy powinny być (patrz niżej)

warning: declaring OPEN instance method in PUBLIC extension

Aby rozwiązać ten problem, należy usunąć modyfikator public dostępu rozszerzenia:

extension UIView { 
    open func doStuff() {...} 
} 

Teraz exte nsion ma poziom dostępu "otwarty" (odziedziczony po open class UIView) , a efektywny poziom dostępu doStuff jest "otwarty" i może być podklasowany.

Dłuższa odpowiedź:

Access Control w Swift odniesienia stwierdza, że ​​

... you can mark an extension with an explicit access-level modifier ... to set a new default access level for all members defined within the extension. This new default can still be overridden within the extension for individual type members.

ale faktycznie można ograniczyć tylko członków typu w rozszerzeniu do tego samego lub niższy dostępu. Niestety, nie znalazłem jednoznacznego odniesienia do tego faktu w dokumentacji.

SE-0117 Allow distinguishing between public access and public overridability stwierdza, że ​​

For example, the true access level of a type member is computed as the minimum of the true access level of the type and the declared access level of the member. If the class is public but the member is open, the true access level is public.

ale nie wyjaśnia, w jaki sposób odnosi się to do rozszerzenia.

Czek można zobaczyć w kodzie źródłowym kompilatora TypeCheckAttr.cpp. Jeśli poziom dostępu elementu jest większy niż poziom dostępu zawierającego przedłużenie wówczas komunikat diagnostyczny diag::access_control_ext_member_more emitowanego:

WARNING(access_control_ext_member_more,none, 
    "declaring %select{PRIVATE|a fileprivate|an internal|a public}0 %1 in " 
    "%select{a private|a fileprivate|an internal|PUBLIC}2 extension", 
    (Accessibility, DescriptiveDeclKind, Accessibility)) 

Należy zauważyć, że poziom „otwarty” brakuje w wyborze i dlatego brakuje w

warning: declaring instance method in PUBLIC extension

+0

Czy to zasługuje na zgłoszenie błędu? – matt

+0

@matt: Zdecydowanie za niekompletny komunikat diagnostyczny. - Wydaje się celowe, że można tylko * obniżyć * dostęp w rozszerzeniu, więc może to być błąd w dokumentacji (albo go nie znalazłem). –

+0

https://bugs.swift.org/browse/SR-3351 –

Powiązane problemy