2016-06-10 13 views
7

Właśnie dowiedziałem się, że private dostęp modyfikator Swift jest na poziomie plików, jak określono w docs pod „Poziomy dostępu”:Dlaczego Swift zezwala na dostęp do prywatnych zmiennych w tym samym pliku?

Prywatny dostęp w Swift różni się od prywatnego dostępu w większości innych języków, jak to scoped do otaczającego pliku źródłowego, a nie do deklaracji otaczającej. Oznacza to, że typ może uzyskiwać dostęp do wszelkich jednostek prywatnych, które są zdefiniowane w tym samym pliku źródłowym, co on, ale rozszerzenie nie może uzyskać dostępu do prywatnych elementów tego typu, jeśli jest zdefiniowane w oddzielnym pliku źródłowym.

Więc to oznacza następujący kod zostanie skompilowany, gdy typy są w tym samym pliku:

class FirstType { 
    private var privateProperty: String = "" 
} 

class SecondType { 
    private let firstType = FirstType() 

    func messWithFirstType() { 
     firstType.privateProperty = "" // this compiles and works! 
    } 
} 

O ile widzę, to łamie encapsulation całkowicie. Z drugiej strony dobrze byłoby, gdyby niektóre powiązane typy były pogrupowane w tym samym pliku dla czytelności, zwłaszcza jeśli powiązane typy są małe, jak wyliczenia.

Prywatne rozszerzenia są wyjątkiem, ponieważ rozszerzają ten sam typ pliku, jaki ma zawierać plik. A prywatne rozszerzenia przynoszą około nice things.

Czy istnieje inny powód, poza modyfikowaniem rozszerzeń prywatnych, dla modyfikatora dostępu do pliku o zakresie private znajdującego się w Swift?

+2

Nie byłbym tak szybki, by powiedzieć, że łamie hermetyzację. Jeśli masz dwie klasy, które nie są ze sobą powiązane (i nie powinny wiedzieć o swoich wewnętrznych cechach), to prawdopodobnie nie powinny znajdować się w tym samym pliku źródłowym. –

+4

Powiązane: [Kontrola dostępu i ochrona] (https://developer.apple.com/swift/blog/?id=11) na blogu Swift. –

+0

@CraigOtis jakie typy można zdefiniować jako "powiązane", aby mogły one zadziałać między sobą? Dwie dyskretne klasy nie powinny wiedzieć o swoim prywatnym okresie składowym. Opieram się na posiadaniu wszystkich typów we własnych plikach źródłowych, nawet malutkich. –

Odpowiedz

7

To nie jest dla mnie jasne, dlaczego private został wdrożony w odniesieniu do plików, ale mieć pewność, że Swift ludzie wiedzą nie jest to jedyne możliwe znaczenie private i że nie jest idealna dla pewnych celów i pracujemy nad jego zmianą. Na stole znajduje się już proposal, zaakceptowany dla Swift 3, który zmieni bieżący private w fileprivate i doda nowy poziom private, który będzie ograniczony do typu, a nie do pliku. Możesz spodziewać się, że stanie się to częścią Swift 3 w najbliższej przyszłości.

+0

Po prostu spóźniłeś się na imprezę. Możesz przeczytać [dyskusję] (http://thread.gmane.org/gmane.comp.lang.swift.evolution/9334) po rozłożeniu. – matt

+2

Gotowe w Swift 3.0: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html#//apple_ref/doc/uid/TP40014097-CH41-ID3 – KarimIhab

1

Kiedy zastanawiasz się nad wszystkim, co wydaje się "dziwne" w Swift, przez większość czasu odpowiedź brzmi "z powodu Celu C".

jakiegoś punktu widzenia, uważam, 3 poziom dostępu wspólne dla wielu nowoczesnych języków programowania:

  1. private: dostępny tylko w tej klasie, w której jest zdefiniowana.
  2. protected: dostępne tylko dla klasy, w której jest zdefiniowana i jej podklas.
  3. public: dostępne dla każdego programu zewnętrznego.

Weźmy jeden krok dalej wstecz, do świata C. C ma modyfikator dostępu w ogóle, nie jest językiem OOP. Jednak w rzeczywistości jest bliżej posiadania prywatnego/publicznego systemu. Jeśli chcesz, aby inne programy znały Twoje symbole (funkcje, makra, typy danych itp.), Możesz je zdefiniować w pliku nagłówkowym (.h). Jeśli nie, możesz je zdefiniować w pliku źródłowym (.c) lub w prywatnym pliku nagłówkowym.Niezależnie od programu zainteresowany symbol będzie zawierać odpowiedni plik nagłówka:

#include "foo.h" 

Ten #include jest nie więcej niż kompilatora wspomaganego kopia & pasty. Kompilator skopiuje wszystkie symbole z foo.h i ponownie je odczyta w pliku źródłowym.

Ponieważ Objective-C jest ścisłym nadzbiorem C, każdy ważny program C jest również ważnym programem Objective-C. Objective-C kontynuuje tę tradycję: zadeklarować publicznych metod w pliku nagłówkowym, zachować prywatny deklarację metody do pliku wdrażania:

// ------------------------------------------ 
// MyClass.h 
// ------------------------------------------ 
@interface MyClass: NSObject 
- (void) publicMethod; 
@end 


// ------------------------------------------ 
// MyClass.m 
// ------------------------------------------ 
#import "MyClass.h" 

// Declare your private methods here. 
// You can move this to a separate file, i.e. MyClass+Private.h if you want 
@interface MyClass() 
- (void) privateMethod; 
@end 

@implementation MyClas  
- (void) publicMethod() { ... } 
- (void) privateMethod() { ... } 
@end 

Tak w skrócie, Objective-C wydaje się dziedziczyć C system w deklaracji publicznych/prywatnych. Jednak Objective-C jest bardzo dynamicznym językiem. Możesz zapytać swoje środowisko uruchomieniowe o wszystkie metody do klasy, prywatnej lub publicznej. Kontrola dostępu w Objective-C to raczej "używaj tego, co ci powiem w dokumentacji", niż "ta metoda jest dla Ciebie niedostępna".

To stanowi paradoks: jak wdrożyć protected w Objective-C? Na to nie ma dobrej odpowiedzi. Jeden wspólny wzór jest przeniesienie wszystkich chronionych metod w osobnym pliku deklaracji i importować je do głównej klasy i realizacji podklas:

// ------------------------------------------ 
// MyClass+Protected.h 
// ------------------------------------------ 
@interface MyClass (Protected) 
- (void) protectedMethod; 
@end 

// ------------------------------------------ 
// MySubClass.m 
// ------------------------------------------ 
#import "MyClass+Protected.h" 
... 

Swift po prostu kontynuuje tę tradycję, lepiej lub gorzej. Istnieje an accepted proposal, aby zmienić to w Swift 3. Jeśli tak, to Chris Lattner i zespół Swift wykazali niewielkie podobieństwo do przeszłości i spuścizny C. Możesz zobaczyć dowód na to w Swift 2.2 z usunięciem ++ i stylu C for pętle.

+0

Doceń swoją odpowiedź. Mam podejrzenia, że ​​to zachowanie jest w jakiś sposób zakorzenione w świecie Objective-C. Ale nadal nie jest dla mnie jasne, dlaczego dokładnie to zrobiono. –

+0

Pewien kontekst historyczny: Apple zatrudnił Chrisa Lattnera dzięki imponującym pracom nad kompilatorem Clang. Jego pierwszy projekt w Apple prawdopodobnie dodał obsługę ObjC w Clangu. Po drodze albo on, albo jakiś starszy pracownik Apple zaproponował pomysł zupełnie nowego języka, który znamy teraz jako Swift. Miał głębokie zaangażowanie w ObjC. A kiedy już umysł zostanie przeszkolony w określony sposób, masz tendencję do podążania za swoim doświadczeniem. –

+0

Oczywiście może to być bardziej skomplikowane, jak niektórzy starsi inżynierowie z Apple tak przyzwyczaili się do ObjC i naciskali na zespół Swift, aby używał modyfikatora dostępu w stylu ObjC. Jestem bardzo szczęśliwy, że to się zmieni –

Powiązane problemy