2016-10-05 23 views
6

Mam następujące funkcję w Swift 3Co oznacza() w Swift?

func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void) 
    { 
    ordersStore.fetchOrders { (orders:() throws -> [Order]) -> Void in 
     do { 
     let orders = try orders() 
     completionHandler(orders) 
     } catch { 
     completionHandler([]) 
     } 
    } 
    } 
  1. Co _ completionHandler argumentem fetchOrders oznacza?
  2. Co oznacza (orders:() throws -> [Order])?

PS: Jestem nowy iOS i Swift

+2

Czytając rozdział „Funkcje” W książce Swift odniesienia może być pomocne ... –

Odpowiedz

7

Jest sporo tu, więc będziemy rozbicie go jeden kawałek na raz:

func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void) 
  • Jest to funkcja zwana fetchOrders.
  • Ma jeden parametr (completionHandler) i nic nie zwraca.
  • Pierwsza _ wskazuje, że nie ma "zewnętrznej nazwy" pierwszego parametru. Oznacza to, że nie musisz tego oznaczać (w rzeczywistości nie możesz). (Z subtelnych powodów, które tak naprawdę nie mają znaczenia tutaj, wierzę, że autor popełnił błąd używając _ tam, i nie zrobiłbym tego.)
  • completionHandler to "nazwa wewnętrzna", jaki parametr nazywa się wewnątrz funkcja.
  • Typ completionHandler to (_ orders: [Order]) -> Void. Złamiemy to teraz.
    • Ta wartość jest zamknięta, która pobiera [Order] (tablica Order) i zwraca Void. Nieformalnie oznacza to "nic nie zwraca", ale dosłownie oznacza, że ​​zwraca pustą krotkę ().
    • Składnia _ orders: jest w praktyce komentarzem. Zasadniczo nazwa _ jest nazwą zewnętrzną (ale jest to jedyna prawnie zewnętrzna nazwa zamknięcia), a orders jest nazwą wewnętrzną, ale w rzeczywistości parametry zamknięcia nie mają nazw w żaden znaczący sposób, więc jest to czysto informacyjne.
    • Uważam, że jest to słabe wykorzystanie systemu komentowania parametrów zamknięcia.Od orders mówi nam nic więcej niż [Order], bym go pominął i zrobił typ tylko ([Order]) -> Void.

Teraz przechodzimy do następnego wiersza:

ordersStore.fetchOrders { (orders:() throws -> [Order]) -> Void in 
  • To wywołuje metodę fetchOrders na ordersStore. Z tego kodu możemy stwierdzić, że fetchOrders przyjmuje parametr zamknięcia. Jest to tak zwana składnia "końcowe zamknięcie" w Swift i dlatego nie użyłbym _ do naszego zamknięcia. Przy składni zamknięcia końcowego zewnętrzna nazwa parametru nie jest potrzebna.
  • Autor podał tutaj informacje o typie, które prawdopodobnie nie były konieczne, ale i tak możemy je zbadać. Prawdopodobnie zostałoby to napisane jako { orders in, ale prawdopodobnie czytelnik byłby zaskoczony tym nieco niecodziennym kodem.
    • Przekazano nam zamknięcie o nazwie orders, które nie przyjmuje niczego i zwraca [Order] lub powoduje błąd. Zasadniczo jest to sposób, aby powiedzieć, że fetchOrders może zawieść.
    • Autor pracuje nad niezręcznością w systemie Swift throws, który nie ma naturalnego sposobu wyrażania asynchronicznej akcji, która może zawieść. Jest to jeden sposób, aby to naprawić; przekazujesz funkcję rzucania (to znaczy możliwą awarię). Nie faworyzuję tego podejścia, preferuję użycie enum Result dla tej sprawy, ponieważ myślę, że skaluje się lepiej i unika możliwych niezamierzonych efektów ubocznych, ale to jest dyskusyjny punkt (a społeczność Swift tak naprawdę nie zdecydowała, jak sobie z tym poradzić powszechny problem).

To wszystko prowadzi nas do:

do { 
    let orders = try orders() 
    completionHandler(orders) 
    } catch { 
    completionHandler([]) 
    } 
  • To gdzie zamknięcie orders jest oceniany. (Jest to bardzo ważne, jeśli wystąpią efekty uboczne, jeśli wystąpią one, które mogą znajdować się w innej kolejce, niż zamierzano, to jeden z powodów, dla których nie faworyzuję tego wzorca). Jeśli zamknięcie się powiedzie, zwrócimy wynik , w przeciwnym razie zwracamy [] poniżej w catch.
    • W tym szczególności przypadku podejście throws jest nieco głupie, bo jest cicho spłaszczone do [] nawet bez wiadomości dziennika. Jeśli nie przejmujemy się tymi błędami, powinna ona powrócić dopiero po [] i nie być pomylona z throws. Ale możliwe jest, że inni rozmówcy sprawdzają błędy.
  • W każdym przypadku nazywamy zamknięcie completionHandler naszym wynikiem, łącząc je z powrotem z naszym oryginalnym rozmówcą.

to zrobić blok/catch mogło być prościej zapisać jako:

let completedOrders = try? orders() ?? [] 
completionHandler(completedOrders) 

To czyni go bardziej zrozumiałym, że jesteśmy ignorując błędy, obracając ją w opcjonalny i pozwala uniknąć powielania kodu podczas rozmowy do completionHandler.

(ja po prostu dodać dodatkowy let wiązania, aby kod trochę łatwiejsze do odczytania;. Nie jest to konieczne)

+0

Tego nie można było wyjaśnić lepiej. –

+0

Czy ktoś może wyjaśnić, jak i dlaczego ten wzorzec może sprawić, że program obsługi kończy się w innej kolejce? – Jay

+1

@Jay W innej kolejce niż co? (W GCD nie ma "aktualnej kolejki". Jest to bardzo powszechne nieporozumienie dotyczące działania kolejek.) Jeśli metoda wykonuje pracę w wątku w tle (wątek nie jest kolejką), prawdopodobnie wykona procedurę obsługi zakończenia wątek po zakończeniu. Wysyłanie do kolejki wymaga dodatkowej złożoności; albo musisz przekazać mu kolejkę, albo musi obiecać określoną kolejkę (taką jak główna kolejka). Ten pierwszy jest dość powszechny w Cocoa. Ta ostatnia jest bardziej powszechna w strukturach zewnętrznych, ale często jest niepożądana. –

2

completionHandler argumentem oznacza, że ​​oczekiwany parametr (o nazwie completionHandler) musi być funkcją, która pobiera listę Order obiektów i nie zwraca żadnej wartości.

2

completionHandler to nazwa zmiennej. W tym konkretnym przykładzie ta zmienna to callback. Wiesz, że jest to funkcja oddzwaniania, ponieważ (orders: [Order]) -> Void jest to typ danych; w tym szczególnym przypadku wspomniany typ danych jest funkcją, która odbiera tablicę obiektów Order w zmienneji nie ma wartości zwracanej (część Void).

TL, DR:

  1. to nazwę zmiennej typu:
  2. funkcją odbiera tablicę Order jako parametr i działa jako zwrotnego.