Możliwe jest dodawanie rozszerzeń do istniejących typów obiektów Swift za pomocą rozszerzeń, zgodnie z opisem w specyfikacji języka .
Dzięki temu możliwe jest tworzenie rozszerzeń takich jak:
extension String {
var utf8data:NSData {
return self.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
}
}
Jaka jest jednak najlepsza praktyka nazywania plików źródłowych Swift zawierających takie rozszerzenia?
W przeszłości konwencja była używana extendedtype+categoryname.m
dla typu Objective-C, jak omówiono w przewodniku Objective-C . Ale przykład Swift nie ma nazwy kategorii, a nazywanie jej String.swift
nie wydaje się odpowiednie.
Tak więc pytanie brzmi: biorąc pod uwagę powyższe String
rozszerzenie, jak powinien się nazywać szybki plik źródłowy?
ios
objective-c
swift
xcode
AlBlue
źródło
źródło
ClassName+ExtensionName
formatem i których nie widzę zbyt wielu ludzi nadal używa. Poza tym uważam, że jest to niezgrabne zamiast po prostu definiowania klas i rozszerzeń razem lub nadawania plikowi lepszej nazwyFooAbleTypes
i definiowania instancji w agregacji.Extensions.swift
. W ten sposób nie stracisz ich z oczu, a nowicjusze w bazie kodu natychmiast je zauważą. I wolałbym, aby jednorazowe rozszerzenia były prywatne w stosunku do pliku, w którym są potrzebne.Odpowiedzi:
Większość przykładów, które widziałem, naśladuje podejście Objective-C. Przykładowe rozszerzenie powyżej to:
String+UTF8Data.swift
Zaletą jest to, że konwencja nazewnictwa ułatwia zrozumienie, że jest to rozszerzenie i która klasa jest rozszerzana.
Problem z używaniem,
Extensions.swift
a nawetStringExtensions.swift
polega na tym, że nie można wywnioskować przeznaczenia pliku na podstawie jego nazwy bez patrzenia na jego zawartość.Używanie
xxxable.swift
podejścia używanego przez Javę działa dobrze w przypadku protokołów lub rozszerzeń, które definiują tylko metody. Ale znowu, powyższy przykład definiuje atrybut, więcUTF8Dataable.swift
nie ma to większego sensu gramatycznego.źródło
ExtendedType+Functionality.swift
, czy dobrym zwyczajem jest sortowanie wszystkichString
rozszerzeń, na przykład, do ich własnego podfolderu (tj.String
LubString Extensions
) wExtensions
folderze? A może lepiej jest po prostu przechowywać wszystkie pliki rozszerzeń na tym samym poziomie wExtensions
folderze?Nie ma konwencji Swift. Nie komplikuj:
Tworzę jeden plik dla każdej rozszerzanej klasy. Jeśli użyjesz jednego pliku dla wszystkich rozszerzeń, szybko stanie się on dżunglą.
źródło
Wolę,
StringExtensions.swift
dopóki nie dodam zbyt wielu rzeczy, aby podzielić plik na coś takiego jakString+utf8Data.swift
iString+Encrypt.swift
.Jeszcze jedno, połączenie podobnych plików w jeden przyspieszy budowanie. Zobacz Optymalizacja-Swift-Build-Times
źródło
Jeśli masz uzgodniony przez zespół zestaw wspólnych i różnych ulepszeń, wrzucenie ich razem jako Extensions.swift działa jako rozwiązanie pierwszego poziomu Keep-It-Simple. Jednak w miarę wzrostu złożoności lub większego zaangażowania rozszerzeń potrzebna jest hierarchia, aby zamknąć złożoność. W takich okolicznościach polecam następującą praktykę wraz z przykładem.
Miałem klasę, która rozmawiała z moim zapleczem, o nazwie
Server
. Zaczął się rozrastać, aby objąć dwie różne aplikacje docelowe. Niektórzy ludzie lubią duży plik, ale logicznie dzielą się na rozszerzenia. Wolę, aby każdy plik był stosunkowo krótki, więc wybrałem następujące rozwiązanie.Server
pierwotnie dostosował sięCloudAdapterProtocol
i wdrożył wszystkie jej metody. To, co zrobiłem, to przekształcić protokół w hierarchię, czyniąc z niego odniesienie do protokołów podrzędnych:W
Server.swift
mamServer.swift
następnie po prostu implementuje podstawowe API serwera do ustawiania serwera i pobierania wersji API. Prawdziwa praca jest podzielona na dwa pliki:Implementują one odpowiednie protokoły.
Oznacza to, że musisz mieć deklaracje importu w innych plikach (dla Alamofire w tym przykładzie), ale moim zdaniem jest to czyste rozwiązanie pod względem segregowania interfejsów.
Myślę, że to podejście działa równie dobrze w przypadku klas określonych zewnętrznie, jak i własnych.
źródło
Dlaczego to w ogóle debata? Czy powinienem umieścić wszystkie moje podklasy w pliku o nazwie _Subclasses.swift. Myślę, że nie. Swift ma odstępy między nazwami oparte na modułach. Aby rozszerzyć dobrze znaną klasę Swift, potrzebny jest plik odpowiedni do jej przeznaczenia. Mógłbym mieć duży zespół, który utworzyłby plik UIViewExtensions.swift, który nie ma żadnego celu i wprowadziłby w błąd programistów i mógłby być łatwo zduplikowany w projekcie, który nie zostałby zbudowany. Konwencja nazewnictwa Objective-C działa dobrze i dopóki Swift nie ma prawdziwych odstępów między nazwami, jest to najlepsza droga.
źródło
Zamiast dodawać moje komentarze w każdym miejscu, ujawniam je wszystkie tutaj w jednej odpowiedzi.
Osobiście stosuję podejście hybrydowe, które zapewnia zarówno dobrą użyteczność, jak i przejrzystość, a jednocześnie nie zaśmieca powierzchni interfejsu API dla obiektu, który rozszerzam.
Na przykład wszystko, co ma sens, aby być dostępne dla dowolnego ciągu, powinno znaleźć się w
StringExtensions.swift
takich jaktrimRight()
iremoveBlankLines()
.Jednak gdybym miał funkcję rozszerzenia takie jak
formatAsAccountNumber()
byłoby nie pójść w tym pliku, ponieważ „Numer rachunku” nie jest czymś, co naturalnie zastosować do każdego / wszystkie sznurki i ma sens tylko w kontekście rachunków. W takim przypadku utworzyłbym plik o nazwieStrings+AccountFormatting.swift
lub nawetStrings+CustomFormatting.swift
zformatAsAccountNumber()
funkcją, jeśli istnieje kilka typów / sposobów jego sformatowania.Właściwie w tym ostatnim przykładzie aktywnie odradzam mojemu zespołowi używanie takich rozszerzeń w pierwszej kolejności i zamiast tego zachęcam do czegoś podobnego,
AccountNumberFormatter.format(String)
ponieważ w ogóle nie dotyka toString
powierzchni interfejsu API, a nie powinno. Wyjątkiem byłoby zdefiniowanie tego rozszerzenia w tym samym pliku, w którym jest używane, ale i tak nie miałoby ono własnej nazwy pliku.źródło
Wolę mieć znak
+
podkreślający fakt, że zawiera rozszerzenia:String+Extensions.swift
A jeśli plik stanie się zbyt duży, możesz go podzielić w każdym celu:
String+UTF8Data.swift
String+Encrypt.swift
źródło