2016-10-25 11 views
21

Rozważmy klasę obserwacji (również zastosowanie do struktury, jak również) w module:Dlaczego publiczna klasa/struktura w Swift wymaga jawnego publicznego inicjatora?

public class Foo { 
    public func bar() { 
     // method body 
    } 
} 

Uwaga, to nie ma wyraźnego inicjatora; ten przykład nie wymaga specjalnej inicjalizacji. Ta klasa będzie narażona na działanie innych modułów, ponieważ jest oznaczona jako public. Jednak, gdy kod na zewnątrz modułu próbuje ją zainicjować, kompilator narzeka:

let foo = Foo() // 'Foo' initializer is inaccessible due to 'internal' protection level 

W celu zaspokojenia kompilator, muszę określić wyraźne pusty inicjator oznaczony public:

public class Foo { 
    public init() { 
     // This initializer intentionally left empty 
    } 

    public func bar() { 
     // do something useful 
    } 
} 

Dlaczego , jeśli klasa jawnie jest public, czy muszę jawnie zdefiniować publiczny inicjator? Czy nie powinien mieć domyślnie publicznego inicjatora?

Istnieje pokrewne pytanie: here, dotyczące testów jednostkowych, ale uważam, że tak naprawdę nie znajduje się w centrum filozofii projektowania tego, co uważam za zaskakujące.

+2

Powiązane: [W jaki sposób mogę domyślnie upublicznić inicjator dla elementów w Swift?] (Http://stackoverflow.com/questions/26224693/how-can-i-make-public-by -default-the-member-wise-initialiser-for-structs-in-swif) – Hamish

Odpowiedz

15

Oznaczenie klasy jako publicznej niekoniecznie oznacza, że ​​programista chce, aby klasa została zainicjowana publicznie. Na przykład często piszę klasy bazowe, które istnieją wyłącznie dla mnie, aby móc je podklasować. Nadaj tym nadklasom internal inicjatory, aby ich podklasy mogły uzyskać do nich dostęp, ale te w świecie zewnętrznym nie powinny używać ich bezpośrednio. Na przykład Operation w Foundation nie ma dostępnych inicjalizatorów, ale klasa jest publiczna. Po prostu ma być podklasowana. Jest to uważane za klasę abstrakcyjną w Objective-C.

Ponieważ Swift nie zawiera wyraźnego wsparcia dla klas abstrakcyjnych, działanie polegające na tym, że klasa jest publiczna, ale bez publicznych inicjalizatorów, w zasadzie służy jako klasa abstrakcyjna (z wyjątkiem tego, że każda funkcja musi nadal mieć domyślną definicję w samej klasie lub niektóre rozszerzenia protokołu).

Mając to na uwadze, oto kilka zasad SWIFT:

  • Jeśli klasa jest oznaczone private wszystkie zmienne, inits i funkcje domyślnie private.
  • Jeśli twoja klasa jest oznaczona internal (która jest domyślna), public lub open, wszystkie zmienne, inicjały i funkcje będą domyślnie ustawione na internal.
  • Nadklasa podklasy musi być przynajmniej tak dostępna.
  • klasy i członkowie klasy zadeklarowani jako w Objective-C są importowani do Swift jako open, z powodu braku takiego rozróżnienia w Objective-C.

Ten drugi to ten, na który się natknąłeś. Domyślnym init jest pobranie domyślnej wartości internal, ponieważ ostatnią rzeczą, którą Swift chce zrobić, jest udostępnienie twojego init jako publicznego interfejsu API, chyba że jest to wyraźnie poinstruowane.

Uwaga: W moich testów (przynajmniej na boisku), wydaje się, że wraz z wprowadzeniem fileprivate:

  • Jeśli klasa jest zadeklarowana private lub fileprivate wydaje się, że domyślne członków klasy do fileprivate chyba jednoznacznie opatrzone przypisami: private.
+0

Twoje sugestie dotyczące używania tej "funkcji" do tworzenia klas abstrakcyjnych są bardzo interesujące i nie brałem pod uwagę. –

+0

To jest naprawdę głupie (jak kilka szybkich decyzji), zwłaszcza, że ​​szybki próbuje przejść od podklasy do używania protokołów. Jeśli autor klas zamierza być abstrakcyjny, powinien zadeklarować inicjator jako wewnętrzny. lub swift powinien po prostu mieć abstrakcyjne słowo kluczowe. –

Powiązane problemy