Darmowy fragment publikacji:
Tytuł oryginału: Mastering Swift 4 - Fourth Edition
Tłumaczenie: Robert Górczyński
ISBN: 978-83-283-4794-6
Copyright © Packt Publishing 2017.
First published in the English language under the title
‘Mastering Swift 4 - Fourth Edition – (9781788477802)’
Polish edition copyright © 2018 by Helion SA. All rights reserved.
All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means,
electronic or mechanical, including photocopying, recording or by any information storage retrieval system,
without permission from the Publisher.
Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej
publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną,
fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje
naruszenie praw autorskich niniejszej publikacji.
Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich
właścicieli.
Autor oraz Helion SA dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne
i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym
ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Helion SA nie ponoszą również żadnej
odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce.
Helion SA
ul. Kościuszki 1c, 44-100 Gliwice
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)
Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/sw4km4
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
Printed in Poland.
• Kup książkę
• Poleć książkę
• Oceń książkę
• Księgarnia internetowa
• Lubię to! » Nasza społeczność
Spis treści
O autorze
O recenzencie technicznym
Wprowadzenie
Rozdział 1. Pierwsze kroki w języku Swift
Czym jest Swift?
Funkcje języka Swift
Plik typu playground
Rozpoczęcie pracy z plikiem typu playground
Typ pliku playground
Wyświetlanie obrazu w pliku playground
Tworzenie i wyświetlanie wykresu w pliku playground
Czym nie jest plik typu playground?
Składnia języka Swift
Komentarze
Średniki
Nawiasy okrągłe
Nawiasy klamrowe
Operator przypisania nie zwraca wartości
Białe znaki w konstrukcjach warunkowych i poleceniach przypisania są opcjonalne
Program wyświetlający komunikat Witaj, świecie!
Podsumowanie
11
12
13
17
18
19
21
21
24
25
28
29
29
30
32
33
33
34
35
35
37
Poleć książkęKup książkęSpis treści
Rozdział 2. Zmienne, stałe, ciągi tekstowe i operatory
Zmienne i stałe
Definiowanie zmiennych i stałych
Bezpieczeństwo typu
Inferencja typu
Jawne określenie typu
Typy liczbowe
Wartości boolowskie
Ciąg tekstowy
Zmienne typu opcjonalnego
Dołączanie wartości typu opcjonalnego
Łączenie wartości typu opcjonalnego
Typy wyliczeniowe
Operatory
Operator przypisania
Operatory porównania
Operatory arytmetyczne
Operator reszty z dzielenia
Złożone operatory przypisania
Trójargumentowy operator warunkowy
Operator logiczny NOT
Operator logiczny AND
Operator logiczny OR
Podsumowanie
Rozdział 3. Krotki i kolekcje
Typy kolekcji w Swifcie
Modyfikowalność
Tablica
Tworzenie oraz inicjalizacja tablicy
Uzyskanie dostępu do elementu tablicy
Zliczanie elementów tablicy
Czy tablica jest pusta?
Dodawanie elementu do tablicy
Wstawienie wartości do tablicy
Zastępowanie elementu tablicy
Usunięcie elementu z tablicy
Połączenie dwóch tablic
Pobranie podtablicy z tablicy
Wprowadzenie wielu zmian w tablicy
Algorytmy dla tablic
Iteracja przez tablicę
Słownik
Utworzenie oraz inicjalizacja słownika
Uzyskanie dostępu do wartości słownika
Zliczanie kluczy lub wartości w słowniku
Czy słownik jest pusty?
Uaktualnienie wartości klucza
4
39
40
41
42
43
43
44
48
48
52
54
55
57
61
61
61
62
62
63
63
63
64
64
64
67
67
68
68
69
70
71
72
72
73
73
73
74
74
75
75
78
79
79
80
80
80
81
Poleć książkęKup książkęDodanie pary klucz-wartość
Usunięcie pary klucz-wartość
Zbiór
Inicjalizacja zbioru
Wstawianie elementów do zbioru
Określenie liczby elementów w zbiorze
Sprawdzenie, czy zbiór zawiera dany element
Iteracja przez zbiór
Usunięcie elementu zbioru
Operacje na zbiorze
Krotka
Podsumowanie
Rozdział 4. Funkcje programu i sterowanie przebiegiem ich działania
Czego nauczyłeś się dotąd z książki?
Nawias klamrowy
Nawias okrągły
Sterowanie przebiegiem działania programu
Konstrukcje warunkowe
Pętla for-in
Pętla while
Konstrukcja switch
Używanie bloków case i klauzul where w konstrukcjach warunkowych
Polecenia transferu kontroli
Funkcje
Funkcja z pojedynczym parametrem
Funkcja z wieloma parametrami
Zdefiniowanie wartości domyślnych parametrów
Zwrot wielu wartości przez funkcję
Zwrot wartości typu opcjonalnego
Dodawanie zewnętrznych nazw parametrów
Używanie parametrów wariadycznych
Parametr inout
Zebranie wszystkiego w całość
Podsumowanie
Rozdział 5. Klasy i struktury
Czym są klasy i struktury?
Podobieństwa między klasami i strukturami
Różnice między klasami i strukturami
Przekazywanie przez wartość kontra przez referencję
Utworzenie klasy lub struktury
Właściwość
Właściwość przechowywana
Właściwość obliczana
Obserwator właściwości
Metoda
Spis treści
81
82
82
82
83
83
84
84
84
84
86
87
89
90
90
90
91
91
94
96
97
101
105
107
107
109
109
110
111
112
113
114
114
115
117
118
118
118
119
120
120
120
122
125
126
5
Poleć książkęKup książkęSpis treści
Własna metoda inicjalizacyjna
Wewnętrzne i zewnętrzne nazwy parametru metody inicjalizacyjnej
Metoda inicjalizacyjna, której działanie może zakończyć się niepowodzeniem
Kontrola dostępu
Dziedziczenie
Nadpisanie metody lub właściwości
Nadpisywanie metody
Nadpisywanie właściwości
Uniemożliwianie nadpisywania
Protokoły
Składnia protokołu
Wymagania właściwości
Wymagania metody
Rozszerzenie
Zarządzanie pamięcią
Sposób działania mechanizmu ARC
Cykl silnych odwołań
Podsumowanie
Rozdział 6. Protokoły i rozszerzenia protokołów
Protokół jako typ danych
Polimorfizm za pomocą protokołów
Rzutowanie typu i protokół
Rozszerzenie protokołu
Czy trzeba używać protokołów?
Biblioteka standardowa Swifta
Podsumowanie
Rozdział 7. Projekt oparty na protokołach
Wymagania
Projekt zorientowany obiektowo
Projekt zorientowany na protokoły
Dziedziczenie protokołu
Kompozycja protokołu
Programowanie zorientowane na protokoły
Używanie klauzuli where z protokołem
Struktura kontra klasa
Struktura tablicy
Podsumowanie
Rozdział 8. Tworzenie bezpiecznego kodu
za pomocą atrybutu available i obsługi błędów
Natywna obsługa błędów
Przedstawienie błędu
Zgłaszanie błędu
Przechwytywanie błędu
Atrybut available
Podsumowanie
6
128
130
130
132
133
135
136
137
138
138
139
139
140
142
143
143
145
149
151
152
154
154
156
163
164
165
167
168
168
174
174
175
176
179
180
181
182
183
184
184
185
187
191
192
Poleć książkęKup książkęRozdział 9. Niestandardowe indeksy
Wprowadzenie do indeksów
Indeks w tablicy Swifta
Tworzenie i używanie niestandardowego indeksu
Niestandardowy indeks tylko do odczytu
Indeks obliczany
Wartość indeksu
Nazwa zewnętrzna dla indeksu
Indeks wielowymiarowy
Kiedy nie należy używać niestandardowego indeksu?
Podsumowanie
Rozdział 10. Typy opcjonalne
Wprowadzenie do typu opcjonalnego
Potrzeba istnienia typów opcjonalnych w Swifcie
Definiowanie wartości typu opcjonalnego
Używanie wartości typu opcjonalnego
Łączenie wartości typu opcjonalnego
Operator koalescencji nil
Podsumowanie
Rozdział 11. Typy generyczne
Wprowadzenie do typu generycznego
Funkcja generyczna
Typ generyczny
Indeks generyczny
Typ powiązany
Podsumowanie
Rozdział 12. Domknięcia
Wprowadzenie do domknięcia
Proste domknięcia
Skrócona składnia domknięcia
Używanie domknięcia wraz z algorytmem tablicy Swifta
Samodzielne domknięcia i wskazówki dotyczące dobrego stylu
Zmiana funkcjonalności
Wybór domknięcia na podstawie wyniku
Utworzenie cyklu silnych odwołań za pomocą domknięć
Podsumowanie
Rozdział 13. Połączenie Swifta i Objective-C
Połączenie Swifta i Objective-C
Kiedy łączyć kod Swifta i Objective-C?
Użycie Swifta i Objective-C w tym samym projekcie
Utworzenie projektu
Dodawanie pliku Swifta do projektu Objective-C
Plik Objective-C Bridging Header — część 1.
Spis treści
193
194
194
195
196
197
197
198
198
201
202
203
203
205
206
206
211
213
214
215
215
216
220
223
224
226
227
227
228
230
233
237
239
242
244
247
249
249
250
251
251
253
255
7
Poleć książkęKup książkęSpis treści
Dodawanie pliku Objective-C do projektu
Klasa Objective-C Messages
Plik Objective-C Bridging Header — część 2.
Klasa Swifta MessageBuilder — dostęp do kodu Objective-C z poziomu Swifta
Klasa Objective-C — dostęp do kodu Swifta z poziomu Objective-C
Podsumowanie
Rozdział 14. Programowanie równoległe i współbieżność
Równoległość i współbieżność
Grand Central Dispatch
Typ DoCalculations
Użycie typów Operation i OperationQueue
Podsumowanie
Rozdział 15. Formatowanie kodu Swifta i przewodnik po jego stylu
Czym jest styl programowania?
Twój styl programowania
Nie używaj średnika na końcu polecenia
Nie używaj nawiasu w konstrukcji warunkowej
Konwencja nazw
Komentarze
Użycie słowa kluczowego self
Stałe i zmienne
Typy opcjonalne
Użycie inferencji typu
Użycie skróconych deklaracji kolekcji
Użycie konstrukcji switch zamiast wielu poleceń if
Nie pozostawiaj w aplikacji kodu umieszczonego w komentarzu
Podsumowanie
Rozdział 16. Podstawowe biblioteki Swifta
System wczytywania adresów URL
URLSession
URLSessionConfiguration
URLSessionTask
URL
URLRequest
HTTPURLResponse
Usługa sieciowa typu REST
Wykonywanie żądania HTTP GET
Wykonywanie żądania HTTP POST
Formatter
DateFormatter
NumberFormatter
FileManager
Kodowanie i dekodowanie danych JSON
Użycie JSONEncoder
Użycie JSONDecoder
Podsumowanie
8
256
258
259
259
260
261
263
264
265
266
272
277
279
280
281
281
281
282
283
284
285
285
286
287
287
287
288
289
290
291
291
291
292
292
292
292
293
296
298
298
300
301
304
305
306
307
Poleć książkęKup książkęRozdział 17. Wzorce projektowe w Swifcie
Czym są wzorce projektowe?
Wzorce konstrukcyjne
Wzorzec singleton
Wzorzec budowniczego
Wzorce strukturalne
Wzorzec mostu
Wzorzec fasady
Wzorzec pełnomocnika
Wzorce operacyjne
Wzorzec polecenia
Wzorzec strategii
Podsumowanie
Skorowidz
Spis treści
309
310
311
312
315
320
320
324
327
330
330
333
335
337
9
Poleć książkęKup książkęPoleć książkęKup książkę6
Protokoły
i rozszerzenia
protokołów
Oglądając pochodzącą z konferencji WWDC 2015 prezentację dotyczącą rozszerzeń proto-
kołów i programowania zorientowanego na protokoły (ang. protocol-oriented programming),
byłem bardzo sceptycznie nastawiony do koncepcji przedstawionych w tej prezentacji. Od
bardzo dawna stosowałem programowanie zorientowane obiektowo i nie byłem przekona-
ny, czy zgodnie z założeniami Apple nowy paradygmat programowania jest w stanie rozwią-
zać wszystkie problemy. Ponieważ nie należę do osób, u których sceptycyzm uniemożliwia
działanie, przygotowałem nowy projekt powielający mój bieżący, ale kod zacząłem tworzyć,
stosując zalecenia Apple dotyczące programowania zorientowanego na protokoły. W nowo
tworzonym kodzie bardzo często korzystałem z rozszerzeń protokołów. Muszę przyznać, że
byłem bardzo zaskoczony tym, iż nowy projekt okazał się znacznie bardziej przejrzysty niż
oryginalny. Jestem przekonany, że obsługa rozszerzenia protokołów stanie się jedną z tych
funkcji, która będzie odróżniała od siebie języki programowania. Wierzę, że podobne funk-
cje pojawią się wkrótce w innych najważniejszych językach programowania.
W rozdziale:
dowiesz się, w jaki sposób protokoły są używane jako typy;
zobaczysz, jak można zaimplementować polimorfizm w Swifcie,
używając protokołów;
zobaczysz, jak można używać rozszerzeń protokołów;
dowiesz się, dlaczego miałbyś korzystać z rozszerzeń protokołów.
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
Wprawdzie rozszerzenia protokołów to w zasadzie lukier syntaktyczny, ale według mnie
stanowią one jedną z najważniejszych funkcji, jaka została dodana do języka programowania
Swift. Dzięki rozszerzeniom protokołów można dostarczać implementacje metod i właści-
wości dowolnemu typowi zgodnemu z protokołem. Aby naprawdę dobrze zrozumieć uży-
teczność protokołów i rozszerzeń protokołów, najpierw należy dokładnie poznać protokoły.
Choć w języku Swift z protokołami mogą być zgodne zarówno klasy, struktury, jak i typy
wyliczeniowe, w tym rozdziale skoncentruję się wyłącznie na klasach i strukturach. Typy wyli-
czeniowe będą używane wtedy, gdy zajdzie potrzeba przedstawienia pewnej liczby przypadków.
Wprawdzie istnieją sytuacje, w których typ wyliczeniowy powinien być zgodny z protoko-
łem, ale zdarza się to bardzo rzadko. Po prostu zapamiętaj, że wszędzie tam, gdzie odwołuję
się do klasy lub struktury, można użyć również typu wyliczeniowego.
Na początek przedstawię protokoły i wyjaśnię, dlaczego są one pełnoprawnymi typami
w Swifcie.
Protokół jako typ danych
Wprawdzie protokół nie implementuje żadnej funkcjonalności, ale jest uznawany za pełno-
prawny typ danych w języku programowania Swift i może być wykorzystywany w taki sam
sposób jak każdy inny typ. Oznacza to możliwość użycia protokołu jako typu parametru lub
wartości zwrotnej funkcji. Ponadto protokół można podać jako typ zmiennej, stałej lub kolekcji.
Spójrz na kilka przykładów, w których zostanie wykorzystany protokół PersonProtocol zde-
finiowany w następujący sposób:
protocol PersonProtocol {
var firstName: String { get set }
var lastName: String { get set }
var birthDate: Date { get set }
var profession: String { get }
init(firstName: String,lastName: String, birthDate: Date)
}
W pierwszym przykładzie protokół zostanie wykorzystany jako typ parametru i wartości
zwrotnej funkcji.
func updatePerson(person: PersonProtocol) - PersonProtocol {
// Miejsce na kod uaktualniający informacje o osobie i zwracający je.
}
W tym przykładzie funkcja updatePerson() akceptuje jeden parametr typu protokołu
PersonProtocol i zwraca wartość również będącą typu wymienionego protokołu. W na-
stępnym przykładzie pokazałem, jak można użyć protokołu jako typu dla stałej, zmiennej
lub właściwości.
var myPerson: PersonProtocol
152
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
W tym przykładzie utworzona została zmienna o nazwie myPerson i typie protokołu
PersonProtocol. Protokół może być również używany jako typ elementu przeznaczonego
do umieszczenia w kolekcji, takiej jak tablica, słownik lub zbiór.
var people: [PersonProtocol] = []
W omawianym przykładzie została utworzona tablica typu protokołu PersonProtocol. Choć
ten protokół nie implementuje żadnej funkcjonalności, mimo wszystko może zostać użyty do
określenia typu. Jednak protokół nie może zostać utworzony w taki sam sposób jak klasa lub
struktura. Wynika to z tego, że protokół nie implementuje żadnej funkcjonalności. Dlatego też
kompilator wygeneruje błąd podczas próby utworzenia egzemplarza protokołu PersonProtocol
w następujący sposób:
var test = PersonProtocol(firstName: Jon , lastName: Hoffman ,
birthDate:bDateProgrammer)
Gdy wymagany jest typ protokołu, można użyć egzemplarza dowolnego typu zgodnego
z tym protokołem. Na przykład po zdefiniowaniu zmiennej typu protokołu PersonProtocol
można jej użyć w dowolnej klasie lub strukturze zgodnej z tym protokołem. Na potrzeby ko-
lejnego przykładu przyjmuję założenie o istnieniu dwóch typów SwiftProgrammer i FootballPlayer
zgodnych z protokołem PersonProtocol.
var myPerson: PersonProtocol
myPerson = SwiftProgrammer(firstName: Jon , lastName: Hoffman ,
birthDate: bDateProgrammer)
print( \(myPerson.firstName) \(myPerson.lastName) )
myPerson = FootballPlayer(firstName: Dan , lastName: Marino ,
birthDate:bDatePlayer)
print( \(myPerson.firstName) \(myPerson.lastName) )
W omawianym fragmencie kodu najpierw utworzyłem zmienną myPerson typu protokołu
PersonProtocol. Następnie przypisałem jej egzemplarz typu SwiftProgrammer oraz wy-
świetliłem wartości właściwości firstName i lastName. Dalej zmiennej myPerson przypisałem
egzemplarz typu FootballPlayer i ponownie wyświetliłem wartości właściwości firstName
i lastName. Warto w tym miejscu wspomnieć, że dla Swifta nie ma znaczenia, czy eg-
zemplarz jest klasą, czy strukturą. Ważna jest jedynie zgodność typu z typem protokołu
PersonProtocol.
Jak wcześniej zobaczyłeś, protokołu PersonProtocol można użyć jako typu dla tablicy. Oznacza
to możliwość wypełnienia tablicy egzemplarzami dowolnego typu zgodnego z protokołem.
Przypominam raz jeszcze, że nie ma żadnego znaczenia, czy typ jest klasą, czy strukturą, o ile
jest zgodny z protokołem. PersonProtocol.
153
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
Polimorfizm za pomocą protokołów
We wcześniejszych przykładach można było dostrzec pewne formy polimorfizmu. Słowo
polimorfizm (ang. polymorphism) pochodzi z języka greckiego, w którym poly oznacza wiel-
kość, a morphe postać. W językach programowania polimorfizm to pojedyncze dziedziczenie
wielu typów (wielu postaci). W przykładach przedstawionych dotąd w rozdziale pojedyn-
czym interfejsem był protokół PersonProtocol, a wiele innych typów było z nim zgodnych.
Polimorfizm pozwala na pracę z wieloma typami w ujednolicony sposób. Aby to zilustro-
wać, można rozbudować poprzedni przykład, w którym została utworzona tablica typów
PersonProtocol, i przeprowadzić iterację przez jej elementy. Następnie dostęp do poszcze-
gólnych elementów tablicy odbywa się za pomocą właściwości i metod zdefiniowanych
w protokole PersonProtocol niezależnie od rzeczywistego typu. Spójrz na kolejny przykład.
for person in people {
print( \(person.firstName) \(person.lastName):\(person.profession) )
}
W rozdziale kilkakrotnie wspomniałem, że po zdefiniowaniu typu zmiennej, stałej, kolekcji
itd. jako protokołu można używać dowolnego egzemplarza typu zgodnego z tym protokołem.
To jest bardzo ważna koncepcja do zrozumienia i zarazem jedna z wielu cech, dzięki którym
protokoły i rozszerzenia protokołów mają tak potężne możliwości.
Podczas użycia protokołu w celu uzyskania dostępu do egzemplarza, jak pokazałem w po-
przednim przykładzie, można używać jedynie metod i właściwości zdefiniowanych w samym
protokole. Jeżeli mają być używane metody i właściwości charakterystyczne dla poszczegól-
nych typów, konieczne jest rzutowanie egzemplarza na ten typ.
Rzutowanie typu i protokół
Rzutowanie typu to sposób na sprawdzenie typu egzemplarza lub potraktowanie egzemplarza
tak, jakby był określonego typu. W Swifcie słowo kluczowe is jest używane do sprawdzenia,
czy egzemplarz jest podanego typu, natomiast słowo kluczowe as służy do potraktowania
egzemplarza jako tego typu.
Na początek pokażę, jak można sprawdzić typ egzemplarza za pomocą słowa kluczowego is.
Spójrz na następujący fragment kodu:
for person in people {
if person is SwiftProgrammer {
print( \(person.firstName) to programista Swifta. )
}
}
154
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
W omawianym przykładzie konstrukcja warunkowa if została użyta do sprawdzenia, czy każ-
dy element tablicy people jest egzemplarzem typu SwiftProgrammer. Jeżeli tak, w konsoli zo-
stanie wyświetlony komunikat informujący, że dana osoba jest programistą Swifta. Wprawdzie
jest to dobra metoda na sprawdzenie, czy masz do czynienia z egzemplarzem konkretnej
klasy lub struktury, ale nie będzie zbyt efektywna, gdy trzeba będzie sprawdzić egzemplarz
pod kątem wielu typów. W takich przypadkach znacznie efektywniejsze będzie użycie kon-
strukcji switch.
for person in people {
switch person {
case is SwiftProgrammer:
print( \(person.firstName) to programista Swifta. )
case is FootballPlayer:
print( \(person.firstName) to sportowiec. )
default:
print( Nie wiadomo, czym się zajmuje \(person.firstName). )
}
}
W omawianym fragmencie kodu pokazałem wykorzystanie konstrukcji switch do sprawdze-
nia typu egzemplarza wszystkich elementów tablicy. Do wykonania tej operacji w poszcze-
gólnych blokach case zostało użyte słowo kluczowe is, aby podjąć próbę dopasowania typu
egzemplarza.
W rozdziale 4. pokazałem, jak można filtrować konstrukcje warunkowe za pomocą klauzuli
where. Tę klauzulę można wykorzystać również wraz ze słowem kluczowym is do filtrowania
tablicy, np.:
for person in people where person is SwiftProgrammer {
print( \(person.firstName) to programista Swifta. )
}
Przechodzę teraz do rzutowania egzemplarza klasy lub struktury na określony typ. Do tego
należy użyć słowa kluczowego as. Ponieważ rzutowanie może zakończyć się niepowodze-
niem — jeśli egzemplarz nie jest określonego typu — więc słowo kluczowe as jest dostar-
czane w dwóch postaciach: as? i as!. W przypadku postaci as?, jeżeli rzutowanie zakończy
się niepowodzeniem, wartością zwrotną będzie nil. Natomiast w przypadku postaci as! nie-
powodzenie rzutowania powoduje wygenerowanie błędu w trakcie działania aplikacji. Dla-
tego też zaleca się użycie as?, o ile nie ma absolutnej pewności dotyczącej typu egzemplarza
lub jeśli sprawdzenie typu egzemplarza odbywa się przed przeprowadzeniem rzutowania.
Wprawdzie w książce przedstawię przykłady rzutowania za pomocą słowa kluczowego as!, ale odra-
dzam jego używanie w rzeczywistych projektach właśnie ze względu na możliwość wygenerowania
błędów w trakcie działania aplikacji.
Spójrz na przykład pokazujący, jak można wykorzystać słowo kluczowe as? do rzutowania
egzemplarza klasy lub struktury na określony typ.
155
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
for person in people {
if let p = person as? SwiftProgrammer {
print( \(person.firstName) to programista Swifta. )
}
}
Ponieważ słowo kluczowe as? zwraca wartość typu opcjonalnego, zastosowany został me-
chanizm dołączania wartości typu opcjonalnego, jak pokazałem w przykładzie.
Po poznaniu podstaw związanych z protokołami można przejść do znacznie bardziej ekscy-
tującej funkcji Swifta, czyli rozszerzenia protokołu.
Rozszerzenie protokołu
Rozszerzenie protokołu pozwala na rozbudowę protokołu mającą na celu dostarczenie im-
plementacji metod i właściwości typom zgodnym z danym protokołem. Rozszerzenie protokołu
pozwala również na przygotowanie często używanych implementacji wszystkim zgodnym
typom, co eliminuje konieczność oddzielnego dostarczania implementacji poszczególnym
typom lub tworzenia hierarchii klas. Wprawdzie rozszerzenie protokołu może nie wydawać się
zbyt ekscytujące, ale gdy tylko poznasz jego potężne możliwości, zmienisz sposób myślenia
dotyczący tworzenia kodu.
Na początek pokażę, jak można użyć rozszerzenia protokołu w bardzo prostym przykładzie.
Pracę należy rozpocząć od zdefiniowania protokołu o nazwie DogProtocol:
protocol DogProtocol {
var name: String { get set }
var color: String { get set }
}
Mając ten protokół, wskazujesz, że każdy zgodny z nim typ musi zawierać dwie właściwości
typu String o nazwach name i color. Kolejnym krokiem jest zdefiniowanie trzech typów
zgodnych z tym protokołem. Nowym typom nadałem nazwy JackRussel, WhiteLab i Mutt,
a ich definicje przedstawiają się następująco:
struct JackRussel: DogProtocol {
var name: String
var color: String
}
class WhiteLab: DogProtocol {
var name: String
var color: String
init(name: String, color: String) {
self.name = name
self.color = color
}
}
156
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
struct Mutt: DogProtocol {
var name: String
var color: String
}
Celowo utworzyłem typy JackRussel i Mutt jako struktury, a typ WhiteLab jako klasę, aby za-
prezentować różnice między nimi oraz pokazać, że są traktowane dokładnie w taki sam spo-
sób podczas pracy zarówno z protokołami, jak i rozszerzeniami protokołów.
Największa różnica widoczna w omawianym przykładzie polega na tym, że typ struktury do-
starcza domyślną metodę inicjalizacyjną, natomiast klasa musi mieć jawnie zdefiniowaną
metodę inicjalizacyjną, aby przypisać wartości początkowe właściwościom.
Przyjmuję założenie, że każdemu typowi zgodnemu z protokołem DogProtocol chcę dostar-
czyć metodę o nazwie speak(). Przed wprowadzeniem rozszerzenia protokołu wymagałoby
to dodania definicji metody do protokołu na przykład w następujący sposób:
protocol DogProtocol {
var name: String { get set }
var color: String { get set }
func speak() - String
}
Gdy metoda jest zdefiniowana w protokole, wówczas trzeba dostarczyć jej implementację
w każdym typie zgodnym z tym protokołem. W zależności od liczby typów zgodnych z da-
nym protokołem implementacja nowej metody może wymagać sporo czasu i utworzenia dużej
ilości kodu. W kolejnym fragmencie kodu pokazałem, jak może przedstawiać się przykładowa
implementacja metody speak():
struct JackRussel: DogProtocol {
var name: String
var color: String
func speak() - String {
return hau hau
}
}
class WhiteLab: DogProtocol {
var name: String
var color: String
init(name: String, color: String) {self.name = nameself.color = color}
func speak() - String {
return hau hau
}
}
struct Mutt: DogProtocol {
var name: String
var color: String
func speak() - String {
return hau hau
}
}
157
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
Wprawdzie przedstawione tutaj rozwiązanie działa, ale na pewno nie zalicza się do szcze-
gólnie efektywnych, ponieważ po każdym uaktualnieniu protokołu konieczne będzie zmo-
dyfikowanie również wszystkich zgodnych z nim typów. To oznacza dużą ilość powielonego
kodu, jak pokazałem w omawianym przykładzie. Ponadto jeśli zajdzie potrzeba zmiany do-
myślnego sposobu działania metody speak(), wówczas trzeba będzie sprawdzić każdą im-
plementację i zmienić tę metodę. W tym momencie do gry wchodzi rozszerzenie protokołu.
Dzięki rozszerzeniu protokołu można wyciągnąć z protokołu definicję metody speak() i zdefi-
niować ją wraz z domyślnym sposobem działania w rozszerzeniu protokołu.
Jeżeli implementujesz metodę w rozszerzeniu protokołu, nie trzeba jej definiować w protokole.
W kolejnym fragmencie kodu pokazałem, jak można zdefiniować protokół i jego rozszerzenie.
protocol DogProtocol {
var name: String { get set }
var color: String { get set }
}
extension DogProtocol {
func speak() - String {
return hau hau
}
}
Na początku znajduje się definicja protokołu DogProtocol wraz z dwiema wcześniej użytymi
właściwościami. Następnie zostało utworzone rozszerzenie protokołu zawierające domyślną
implementację metody speak(). Mając tak przygotowany kod, nie trzeba już teraz dostarczać
implementacji metody speak() we wszystkich typach zgodnych z protokołem DogProtocol,
ponieważ będą one automatycznie otrzymywały implementację jako część protokołu.
Praktyczne zastosowanie takiego rozwiązania pokażę na przykładzie przywrócenia trzem typom
zgodnym z protokołem DogProtocol ich początkowych implementacji. W takim przypadku
metodę speak() powinny otrzymać dzięki rozszerzeniu protokołu.
struct JackRussel: DogProtocol {
var name: String
var color: String
}
class WhiteLab: DogProtocol {
var name: String
var color: String
init(name: String, color: String) {
self.name = name
self.color = color
}
}
struct Mutt: DogProtocol {
var name: String
var color: String
}
158
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
Zobacz teraz, jak przygotowane typy można zastosować w kodzie.
let dash = JackRussel(name: Dash , color: brązowy i biały )
let lily = WhiteLab(name: Lily , color: biały )
let maple = Mutt(name: Buddy , color: brązowy )
let dSpeak = dash.speak() // Wartością zwrotną jest hau hau .
let lSpeak = lily.speak() // Wartością zwrotną jest hau hau .
let bSpeak = maple.speak() // Wartością zwrotną jest hau hau .
Jak widać w omawianym przykładzie, zdefiniowanie metody speak() w rozszerzeniu proto-
kołu powoduje jej automatyczne dodanie do wszystkich typów zgodnych z tym protokołem.
Dlatego też tutaj metoda speak() umieszczona w rozszerzeniu protokołu może być uznawa-
na za domyślną implementację metody, ponieważ można ją nadpisać w poszczególnych im-
plementacjach typów. Na przykład metodę speak() można nadpisać w strukturze Mutt, jak
pokazałem w kolejnym fragmencie kodu.
struct Mutt: DogProtocol {
var name: String
var color: String
func speak() - String {
return Jestem głodny
}
}
Po wywołaniu metody speak() egzemplarza Mutt wartością zwrotną będzie ciąg tekstowy
Jestem głodny.
W tym rozdziale definiowanym protokołom dodaję przyrostek Protocol. Zdecydowałem się na to,
aby wyraźnie pokazać, kiedy mamy do czynienia z protokołami. To nie jest standardowe podejście
w zakresie nadawania nazw typom. Przedstawiony nieco dalej w tekście przykład znacznie lepiej po-
kazuje, jak należy prawidłowo nadawać nazwy protokołom. Więcej informacji na temat konwencji
nazw w języku Swift znajdziesz na stronie https://swift.org/documentation/api-design-guidelines/
#general-conventions.
Zobaczyłeś już, jak można używać protokołów i ich rozszerzeń, przechodzę więc teraz do
znacznie bardziej praktycznego przykładu. W wielu aplikacjach dostępnych na różnych
platformach (iOS, Android, Windows) zachodzi potrzeba weryfikacji danych wejściowych
wprowadzonych przez użytkownika. Taką weryfikację można bardzo łatwo przeprowadzić za
pomocą wyrażeń regularnych. Jednak zwykle nie chcemy, aby różne wyrażenia regularne
były porozrzucane w wielu miejscach kodu źródłowego. Ten problem można bardzo łatwo
rozwiązać poprzez utworzenie oddzielnych klas lub struktur zawierających kod odpowie-
dzialny za przeprowadzenie weryfikacji danych wejściowych. Typy te trzeba jednak zorgani-
zować w określony sposób, aby ułatwić ich użycie i późniejszą konserwację. Przed wprowa-
dzeniem rozszerzenia protokołu w Swifcie trzeba było użyć protokołu do zdefiniowania
wymagań dotyczących weryfikacji danych wejściowych, a następnie utworzyć zgodne z nim
struktury dla każdej potrzebnej operacji sprawdzania danych. Spójrz na rozwiązanie, które
było stosowane przed wprowadzeniem rozszerzenia protokołu.
159
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
Wyrażenie regularne to sekwencja znaków definiujących określony wzorzec. Ten wzorzec może być
następnie używany do przeszukiwania ciągów tekstowych i sprawdzania, czy ciąg tekstowy jest dopa-
sowany do wzorca lub czy zawiera dopasowanie wzorca. Większość języków programowania ma
wbudowany pewien analizator składni wyrażeń regularnych. Jeżeli nie znasz wyrażeń regularnych,
naprawdę warto poświęcić czas na ich opanowanie.
W kolejnym fragmencie kodu przedstawiłem protokół TextValidating definiujący wymagania
dla każdego typu, który ma być używany podczas weryfikacji danych wejściowych.
protocol TextValidating {
var regExMatchingString: String { get }
var regExFindMatchString: String { get }
var validationMessage: String { get }
func validateString(str: String) - Bool
func getMatchingString(str: String) - String?
}
Zgodnie z dokumentem umieszczonym na stronie https://swift.org/documentation/api-design-
guidelines/ protokół wskazujący na obecność czegoś powinien mieć nazwę w postaci rze-
czownika w języku angielskim, natomiast protokół opisujący możliwości powinien mieć nazwę
z przyrostkiem -able, -ible lub -ing. Mając to na uwadze, protokół otrzymał nazwę TextValidating.
W tym protokole zdefiniowałem trzy właściwości i dwie metody, które zgodny z nimi typ
musi implementować. W kolejnych punktach przedstawiłem krótkie omówienie właściwości
wymaganych przez protokół TextValidating.
regExMatchingString. To jest ciąg tekstowy wyrażenia regularnego używanego
do sprawdzenia, czy dane wejściowe składają się jedynie z poprawnych znaków.
regExFindMatchString. To jest ciąg tekstowy wyrażenia regularnego używanego
do pobrania z danych wejściowych nowego ciągu tekstowego zawierającego
jedynie prawidłowe znaki. Ogólnie rzecz biorąc, to wyrażenie regularne jest
używane wtedy, gdy zachodzi potrzeba sprawdzania danych wejściowych
w czasie rzeczywistym podczas wprowadzania informacji przez użytkownika.
Znajduje ono najdłuższy dopasowany prefiks danych wejściowych.
validationMessage. To jest komunikat błędu, który zostanie wyświetlony,
gdy ciąg tekstowy zawiera nieprawidłowe znaki.
Oto krótkie omówienie metod wymaganych przez protokół TextValidating:
validateString(). Ta metoda zwraca wartość true, jeżeli ciąg tekstowy zawiera
jedynie prawidłowe znaki. Aby znaleźć dopasowanie, ta metoda używa właściwości
regExMatchingString.
getMatchingString(). Ta metoda zwraca nowy ciąg tekstowy zawierający jedynie
prawidłowe znaki. Ta metoda jest najczęściej używana, gdy zachodzi potrzeba
sprawdzania danych wejściowych w czasie rzeczywistym podczas wprowadzania
informacji przez użytkownika. Znajduje ona najdłuższy dopasowany prefiks danych
wejściowych. Natomiast do pobrania nowego ciągu tekstowego ta metoda używa
właściwości regExFindMatchString.
160
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
Przechodzę teraz do utworzenia struktury zgodnej z omówionym protokołem. Zadaniem
przedstawionej tutaj struktury jest sprawdzenie, czy ciąg tekstowy danych wejściowych za-
wiera jedynie znaki alfanumeryczne.
struct AlphaValidation1: TextValidating {
static let sharedInstance = AlphaValidation1()
private init(){}
let regExFindMatchString = ^[a-zA-Z]{0,10}
let validationMessage = Dozwolone są jedynie litery.
var regExMatchingString: String {
get {
return regExFindMatchString + $
}
}
func validateString(str: String) - Bool {
if let _ = str.range(of: regExMatchingString,
options: .regularExpression) {
return true
} else {
return false
}
}
func getMatchingString(str: String) - String? {
if let newMatch = str.range(of: regExFindMatchString,
options:.regularExpression) {
return str.substring(with:newMatch)
} else {
return nil
}
}
}
W przedstawionej implementacji regExFindMatchString i validationMessage to właściwości
przechowywane, natomiast regExMatchingString to właściwość obliczana. Ta struktura im-
plementuje również metody validateString() i getMatchingString().
W rzeczywistym projekcie istniałoby wiele różnych typów zgodnych z tym protokołem
przeznaczonych do weryfikacji odmiennych rodzajów danych wejściowych. Jak możesz zo-
baczyć na przykładzie struktury AlphaValidation1, przygotowanie każdego typu przezna-
czonego do weryfikacji wymaga utworzenia znacznej ilości kodu. Ponadto duża część tego kodu
będzie powielona w poszczególnych typach. Kod obu metod i właściwości regExMatchingString
prawdopodobnie zostanie powtórzony w każdej klasie weryfikacji danych. Takie rozwiązanie
jest dalekie od idealnego. Jeżeli jednak chciałbyś uniknąć tworzenia hierarchii klas wraz
z superklasą zawierającą powtarzający się kod (zaleca się preferowanie typu przekazywane-
go przez wartość, a nie przez referencję), to przed wprowadzeniem rozszerzenia protokołu
nie miałeś żadnego innego wyboru. Teraz pokażę, jak zaimplementować rozwiązanie oparte
na rozszerzeniu protokołu.
W przypadku rozszerzeń protokołów należy zmienić sposób myślenia o kodzie. Największa
różnica polega na tym, że nie trzeba i nie należy definiować wszystkiego w protokole. W przy-
padku standardowych protokołów wszystkie metody i właściwości, do których będziesz chciał
mieć dostęp za pomocą interfejsu protokołu, zostaną zdefiniowane w tym protokole.
161
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
Mając do dyspozycji rozszerzenie protokołu, odradza się definiowanie w nim metody lub
właściwości, jeśli ta definicja może być umieszczona w rozszerzeniu protokołu. Dlatego też
w zmodyfikowanej wersji protokołu dotyczącego weryfikacji danych wejściowych TextValidating
może zostać znacznie uproszczony do następującej postaci:
protocol TextValidating {
var regExFindMatchString: String { get }
var validationMessage: String { get }
}
W początkowej wersji protokołu TextValidating były zdefiniowane trzy właściwości i dwie
metody. Jak możesz zobaczyć w zmodyfikowanej wersji, teraz protokół zawiera jedynie dwie
właściwości. Po zdefiniowaniu protokołu TextValidating można przystąpić do przygotowania
rozszerzenia tego protokołu.
extension TextValidating {
var regExMatchingString: String {
get {
return regExFindMatchString + $
}
}
func validateString(str: String) - Bool {
if let _ = str.range(of:regExMatchingString,
options:.regularExpression){
return true
} else {
return false
}
}
func getMatchingString(str: String) - String? {
if let newMatch = str.range(of:regExFindMatchString,
options:.regularExpression) {
return str.substring(with: newMatch)
} else {
return nil
}
}
}
Rozszerzenie protokołu TextValidating zawiera dwie metody i właściwość, które wcześniej
znajdowały się w pierwotnej wersji protokołu, a nie zostały uwzględnione w nowej. Mając
utworzony protokół i jego rozszerzenie, można przystąpić do zdefiniowania typów odpowie-
dzialnych za weryfikację danych wejściowych. W kolejnym fragmencie kodu przedstawiłem
trzy struktury używane do sprawdzenia tekstu wpisanego przez użytkownika.
struct AlphaValidation: TextValidating {
static let sharedInstance = AlphaValidation()
private init(){}
let regExFindMatchString = ^[a-zA-Z]{0,10}
let validationMessage = Dozwolone są jedynie litery.
}
struct AlphaNumericValidation: TextValidating {
162
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
static let sharedInstance = AlphaNumericValidation()
private init(){}
let regExFindMatchString = ^[a-zA-Z0-9]{0,15}
let validationMessage = Dozwolone są jedynie znaki alfanumeryczne.
}
struct DisplayNameValidation: TextValidating {
static let sharedInstance = DisplayNameValidation()
privateinit(){}
let regExFindMatchString = ^[\\s?[a-zA-Z0-9\\-_\\s]]{0,15}
let validationMessage = Dozwolone są jedynie znaki alfanumeryczne.
}
We wszystkich przedstawionych tutaj strukturach weryfikacji danych wejściowych zostały
utworzone statyczne stałe i prywatne metody inicjalizacyjne, co pozwoli na użycie struktury
jako wzorca singleton. Więcej informacji na temat wzorca projektowego singleton znajdziesz
w rozdziale 17.
Po zdefiniowaniu wzorca singleton w poszczególnych typach trzeba przypisać wartości wła-
ściwościom regExFindMatchString i validationMessage. W ten sposób praktycznie zostanie
wyeliminowany powielający się kod. Jedynym powtarzającym się kodem jest wzorzec sin-
gleton — nie zostanie on umieszczony w rozszerzeniu protokołu, aby nie wymagać stosowa-
nia tego wzorca projektowego we wszystkich typach zgodnych z danym protokołem.
Po wprowadzeniu omówionych zmian można zacząć używać nowych typów przeznaczonych
do weryfikacji danych wejściowych użytkownika:
var testString = abc123
var alpha = AlphaValidation.sharedInstance
alpha.getMatchingString(str:testString)
alpha.validateString(str: testString)
W omówionym tutaj przykładzie został utworzony nowy ciąg tekstowy przeznaczony do spraw-
dzenia. Ponadto utworzyłem współdzielony egzemplarz typu AlphaValidation. Następnie metoda
getMatchingString() zostanie użyta do pobrania najdłuższego prefiksu dopasowanego do ciągu
tekstowego, którym w omawianym przykładzie jest abc. Później metoda validateString()
sprawdza ciąg tekstowy, a ponieważ zawiera on cyfry, więc jej wartością zwrotną jest false.
Czy trzeba używać protokołów?
Czy trzeba korzystać z protokołów i ich rozszerzeń, gdy programista ma doświadczenie
w programowaniu zorientowanym obiektowo? Krótka odpowiedź brzmi: nie, jednak stosowa-
nie protokołów jest zalecane. W rozdziale 7. zobaczysz, dlaczego projekt oparty na protoko-
łach oferuje potężne możliwości, i dowiesz się, dlaczego powinieneś preferować styl oparty
na protokołach zamiast stylu programowania zorientowanego obiektowo. Dzięki zrozumie-
niu protokołów i opartego na nich projektu będziesz mógł jeszcze lepiej rozumieć bibliotekę
standardową Swifta.
163
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
Biblioteka standardowa Swifta
Biblioteka standardowa Swifta definiuje podstawową warstwę funkcjonalności potrzebnej
podczas tworzenia aplikacji w języku Swift. Wszystko to, czego dotąd używałem w książce,
pochodzi właśnie z biblioteki standardowej Swifta. Znajdują się w niej definicje najważniej-
szych typów danych, takich jak String, Int i Double. Ponadto biblioteka standardowa definiuje
kolekcje, typy opcjonalne, funkcje globalne i wszystkie protokoły, z którymi są zgodne te typy.
Jedną z najlepszych witryn zawierających wiele informacji na temat biblioteki standardowej
Swifta jest http://swiftdoc.org/. Znajdziesz w niej omówienie wszystkich typów, protokołów,
operatorów i funkcji globalnych tworzących bibliotekę standardową. Ta witryna zawiera
również dokumentację dla tych komponentów.
Pokażę teraz, jak protokoły są używane w bibliotece standardowej. W tym celu posłużę się
dokumentacją pochodzącą z witryny http://swiftdoc.org/. Gdy po raz pierwszy odwiedzisz tę
witrynę, zobaczysz możliwą do przeszukiwania listę wszystkiego, co tworzy bibliotekę stan-
dardową Swifta. Dostępna jest również pełna lista wszystkich typów Swifta, z której można
wybierać interesujące Cię pozycje. Spójrz na typ Array, klikając łącze o tej samej nazwie.
W ten sposób przejdziesz na stronę zawierającą dokumentację wybranego typu.
Strony dokumentacji w witrynie http://swiftdoc.org/ są niezwykle użyteczne i zawierają na-
prawdę wiele informacji na temat różnych typów tworzących bibliotekę standardową oraz
przykłady ich użycia. W tym miejscu przyjmuję założenie, że interesuje Cię sekcja Inheritance
na stronie typu Array, jak pokazałem na rysunku 6.1.
Rysunek 6.1. Sekcja Inheritance na stronie dokumentacji typu Array
Jak możesz zobaczyć, typ Array jest zgodny z dziesięcioma protokołami, choć to tylko wierz-
chołek góry lodowej. Jeżeli klikniesz łącze widoku hierarchii protokołów, otrzymasz pełną
hierarchię protokołów, z którymi jest zgodny typ Array (patrz rysunek 6.2).
Rysunek 6.2. Hierarchia protokołów typu Array
164
Poleć książkęKup książkęRozdział 6. • Protokoły i rozszerzenia protokołów
Dzięki dotychczas przedstawionemu materiałowi nie powinieneś mieć problemów z roz-
szyfrowaniem tego diagramu. Możesz natomiast nie wiedzieć, dlaczego został ułożony w taki
właśnie sposób. W następnym rozdziale dowiesz się, jak projektować aplikacje i frameworki,
wykorzystując podejście oparte na protokołach. Na końcu następnego rozdziału nieco do-
kładniej przedstawię hierarchię protokołów.
Podsumowanie
W tym rozdziale dowiedziałeś się, że protokoły to pełnoprawne typy w Swifcie. Zobaczyłeś
również, jak polimorfizm w Swifcie może zostać zaimplementowany za pomocą protokołów.
Następnie dość dokładnie omówiłem rozszerzenia protokołów i przykłady ich użycia w Swifcie.
Protokoły i ich rozszerzenia są podstawą stosowanego przez Apple nowego paradygmatu
programowania zorientowanego na protokołach. Ten nowy model programowania ma poten-
cjał do zmiany sposobu tworzenia kodu źródłowego. Wprawdzie ten rozdział nie został po-
święcony temu nowemu paradygmatowi, ale przedstawiony tutaj materiał pozwolił na solid-
ne poznanie podstaw dotyczących protokołów i ich rozszerzeń. Ta wiedza będzie niezbędna
podczas poznawania tego nowego modelu programowania.
W następnym rozdziale pokażę, jak można używać protokołów i ich rozszerzeń podczas
projektowania aplikacji.
165
Poleć książkęKup książkęSwift 4. Koduj jak mistrz
166
Poleć książkęKup książkęSkorowidz
A
D
ABI, application binary interface, 18
adapter, 320
adres URL, 290
algorytm
filter(), 76
forEach(), 77
map(), 77
sort(), 76
sorted(), 76
algorytmy dla tablic, 75, 233
ARC, 143
atrybut available, 191
B
bezpieczeństwo typu, 42
białe znaki, 35
biblioteka standardowa, 164
biblioteki, 289
blok case, 101
błędy, 184
przechwytywanie, 187
zgłaszanie, 185
budowniczy, 311
DateFormatter, 298
definiowanie zmiennych, 41
deklaracje kolekcji, 287
dekorator, 320
dołączanie wartości, 54
typu opcjonalnego, 285, 286, 305
domknięcia, 227
cykl silnych odwołań, 244
samodzielne, 237
składnia, 230
wybór, 242
z algorytmem tablicy, 233
zmiana funkcjonalności, 239
dostęp
do elementu tablicy, 70
do kodu Objective-C, 259
do kodu Swifta, 260
do wartości słownika, 80
otwarty, 132
prywatny, 132
prywatny dla pliku, 132
publiczny, 132
wewnętrzny, 132
dziedziczenie, 118, 133
protokołu, 174
C
ciąg tekstowy, 48
cykl silnych odwołań, 145, 244
F
fabryka abstrakcyjna, 311
fasada, 320
FIFO, 265
FileManager, 301
Poleć książkęKup książkęSkorowidz
filtrowanie danych, 101, 102
formatowanie kodu, 279
Formatter, 298
framework
Cocoa, 24
UIKit, 24
funkcje, 107, 282
generyczne, 216
języka, 19
parametry wariadyczne, 113
wartości domyślne parametrów, 109
z pojedynczym parametrem, 107
z wieloma parametrami, 109
zewnętrzne nazwy parametrów, 112
zwrot wartości typu opcjonalnego, 111
zwrot wielu wartości, 110
G
Grand Central Dispatch, 265
H
hierarchia
klas, 169
protokołów, 164
HTTPURLResponse, 292
I
implementacja wzorca
budowniczego, 315
fasady, 325
mostu, 321
pełnomocnika, 328
polecenia, 331
singleton, 313
strategii, 333
indeksy, 118, 193
generyczne, 223
nazwa zewnętrzna, 198
niestandardowe, 195, 201
obliczane, 197
tablic, 194
tylko do odczytu, 196
wielowymiarowe, 198
inferencja typu, 20, 43, 286
inicjalizacja
słownika, 79
tablicy, 69
zbioru, 82
338
interfejs binarny aplikacji, ABI, 18
IP, internet protocol, 114
iteracja przez tablicę, 78
iterator, 330
J
jawne określenie typu, 43
JSON, 304
JSONDecoder, 306
JSONEncoder, 305
K
katalog Resources, 26
klasa, 118, 180
BlockOperation, 273
DateFormatter, 298
FileManager, 301
Formatter, 298
HTTPURLResponse, 292
MessageBuilder, 259
Messages, 258
NumberFormatter, 300
Operation, 276
URLRequest, 292
URLSession, 291
URLSessionConfiguration, 291
konstrukcje warunkowe, 91, 101
kontrola dostępu, 132
konwencja nazw, 282
krotka, 20, 86, 210
klauzula where, 101, 179
kodowanie danych JSON, 304
kolejka
FIFO, 265
główna, 266, 271
szeregowa, 266, 269
współbieżna, 266, 268
kolekcje, 67
komentarze, 30, 283
kompozycja protokołu, 175
kompozyt, 320
konstrukcja
for-case, 102
guard, 93
if, 91
if-case, 104
if-else, 92
switch, 20, 97, 287
Poleć książkęKup książkęL
liczby
całkowite, 44
podwójnej precyzji, 46
zmiennoprzecinkowe, 46
Ł
łańcuch zobowiązań, 330
łączenie
kodu, 250
wartości, 55
M
mechanizm ARC, 143
mediator, 330
metoda, 118, 126, 282
addOperation(), 274
async(), 271
asyncAfter(), 272
sync(), 271
metody
dealokujące, 118
inicjalizacyjne, 118, 128, 130
nadpisywanie, 136
wytwórcze, 311
modyfikowalne kolekcje, 20
modyfikowalność, 68
most, 320
N
nadpisywanie
metody, 136
właściwości, 137
natywna obsługa błędów, 184
nawiasy
klamrowe, 33, 90
okrągłe, 33, 90
nil, 213
NumberFormatter, 300
O
Objective-C, 249, 251
obserwator, 330
właściwości, 125
obsługa błędów, 184
odwiedzający, 330
Skorowidz
okno
pliku typu playground, 21, 22
powitalne Xcode, 22
operacje na zbiorze, 84
operator
koalescencji nil, 213
AND, 64
NOT, 63
OR, 64
reszty z dzielenia, 62
warunkowy trójargumentowy, 63
operatory
arytmetyczne, 62
logiczne, 63
porównania, 61
przypisania, 34, 63
P
pamiątka, 330
pamięć, 143
panel nawigacyjny, 25
para klucz-wartość, 81
parametr inout, 114
parametry wariadyczne, 113
pełnomocnik, 320
pętla
for-in, 84, 94
repeat-while, 97
while, 96
plik Bridging Header, 255, 259
pliki playground, 21, 29
tworzenie wykresu, 28
typ iOS, 24
typ tvOS, 24
wyświetlanie obrazu, 25
polecenie, 330
break, 105
continue, 105
fallthrough, 106
polimorfizm, 154
poziomy dostępu, 132
programowanie
równoległe, 263
zorientowane na protokoły, 20, 151, 167, 174
zorientowane obiektowo, 151, 168
projekt Objective-C, 251
dodawanie pliku, 253, 256
dostęp do kodu, 259
klasa Messages, 258
plik Bridging Header, 255, 259
339
Poleć książkęKup książkęSkorowidz
protokoły, 20, 138, 151
dziedziczenie, 174
jako typ danych, 152
klauzula where, 179
kompozycja, 175, 179
polimorfizm, 154
projekt, 174
rozszerzenie, 156
składnia, 139
typu Array, 164
wymagania metody, 140
wymagania właściwości, 139
protokół IP, 114
prototyp, 312
przeciążanie operatorów, 20
przekazywanie
przez referencję, 119
przez wartość, 119
pyłek, 320
R
REPL, read-evaluate-print-loop, 21
REST, 292
rozszerzenia, 118, 142
protokołów, 151, 156
równoległość, 264
rzutowanie typu, 154
S
separator, 36
singleton, 312
składnia
domknięcia, 20, 230
języka, 29
protokołu, 139
słownik, 79
dostęp, 80
inicjalizacja, 79
para klucz-wartość, 80–82
słowo kluczowe self, 284
stałe, 40, 282, 285
stan, 330
sterowanie przebiegiem działania programu, 91
strategia, 330
struktura, 118, 180
tablicy, 181
styl programowania, 280, 281
superklasa, 169
Swift, 18
system plików, 301
340
średnik, 32, 281
Ś
T
tablica, 68, 181
algorytmy, 75
dodawanie elementu, 72
dostęp do elementu, 70
indeksy, 194
inicjalizacja, 69
łączenie tablic, 74
pobranie podtablicy, 74
tworzenie, 69
usunięcie elementu, 73
wprowadzenie wielu zmian, 75
wstawienie wartości, 73
zastępowanie elementu, 73
zliczanie elementów, 71
terminator, 36
trójargumentowy operator warunkowy, 63
tworzenie
cyklu silnych odwołań, 244
klasy, 120
kolejki, 267
niestandardowego indeksu, 195
słownika, 79
struktury, 120
tworzenie wykresu, 28
typ, 118
DoCalculations, 266
JSONDecoder, 306
JSONEncoder, 305
Operation, 272
OperationQueue, 272
pliku playground, 24
typy
generyczne, 20, 215, 220
kolekcji, 67
liczbowe, 44
opcjonalne, 20, 203, 210, 285
powiązane, 224
własne, 282
wyliczeniowe, 20, 57
U
URL, 290, 292
URLRequest, 292
URLSession, 291
URLSessionConfiguration, 291
Poleć książkęKup książkęURLSessionTask, 291
usługa sieciowa typu REST, 292
usprawnienia, 20
użycie
inferencji typu, 286
JSONDecoder, 306
konstrukcji switch, 287
nawiasu, 281
skróconych deklaracji kolekcji, 287
średnika, 281
W
wartości
boolowskie, 48
typu opcjonalnego, 206–211
indeksu, 197
wcięcia, 283
wczytywanie adresów URL, 290
właściwości
nadpisywanie, 137
obliczane, 120, 122
przechowywane, 120
współbieżność, 264
wykres
tworzenie, 28
wyświetlanie, 28
wyświetlanie
obrazu, 25
wykresu, 28
wzorce
konstrukcyjne, 311
operacyjne, 330
projektowe, 309
strukturalne, 320
Skorowidz
wzorzec
budowniczego, 315
fasady, 324
mostu, 320
pełnomocnika, 327
polecenia, 330
singleton, 312
strategii, 333
X
Xcode
okno powitalne, 22
opcje menu, 23
Z
zapis pliku, 254
zarządzanie pamięcią, 143
zbiór, 82
inicjalizacja, 82
określenie liczby elementów, 83
operacje, 84
usuwanie elementów, 84
wstawianie elementów, 83
zmienne, 40, 282, 285
typu opcjonalnego, 52
Ż
żądanie
GET, 293
POST, 296
341
Poleć książkęKup książkęNotatki
342
Poleć książkęKup książkę
Pobierz darmowy fragment (pdf)