УДК 004.432
ББК 32.972.1
B26
B26 Чейрд ин’т Вейн
Swift. Подробно / Пер. с англ. Д. А. Беликова. – М.: ДМК Пресс, 2020. – 412 с.
ISBN 978-5-97060-780-0
Данная книга знакомит вас с навыками, необходимыми для создания
профессионального программного обеспечения для платформ Apple, таких
как iOS и MacOS. Вы освоите такие мощные методы, как обобщение,
эффективная обработка ошибок, протокольно-ориентированное программирование
и современные шаблоны Swift.
ней.
Издание рассчитано на программистов продвинутого и среднего уровУДК
004.432
ББК 32.972.1
Все права защищены. Любая часть этой книги не может быть воспроизведена
в какой бы то ни было форме и какими бы то ни было средствами без письменного
разрешения владельцев авторских прав
Материал, изложенный в данной книге, многократно проверен. Но, поскольку
вероятность технических ошибок все равно существует, издательство не может гарантировать
абсолютную точность и правильность приводимых сведе ний. В связи
с этимиздательство не несет ответственности за возможные ошибки, связанные
с использованием книги.
ISBN 978-5-97060-780-0 (рус.)
ISBN 978-1-61729-518-8 (анг.)
©2019 by Manning Publications Co.
© Оформление, издание, ДМК Пресс, 2020
Стр.5
Содержание
Предисловие
Благодарности
Об этой книге
Почему эта книга?
Подходит ли вам эта книга?
Чем эта книга не является
Книжный форум
Об авторе
Особый акцент на практических сценариях
Дорожная карта
О коде
Об иллюстрации на обложке
Предисловие от издательства
Отзывы и пожелания
Список опечаток
Нарушение авторских прав
Глава 1. Введение
1.1. «Золотая середина» SWIFT
1.2. Под поверхностью
1.3. Минусы Swift
1.3.1. Стабильность ABI
1.3.2. Строгость
1.3.3. Сложность протоколов
1.3.4. Параллелизм
1.3.5. Отход от платформ Apple
1.3.6. Время компиляции
1.4. Чему вы научитесь
14
15
16
16
17
18
18
18
24
25
25
25
26
26
26
26
28
28
30
30
30
1.5. Как извлечь максимум из этой книги
1.6. Минимальная квалификация
1.7. Версия Swift
Глава 2. Моделирование данных с помощью перечислений
2.1. OR в сравнении с AND
2.1.1. Моделирование данных с помощью структуры
2.1.2. Превращаем структуру в перечисление
2.1.3. Выбор между структурами и перечислениями
2.2. Перечисления для полиморфизма
2.3.1. Формирование модели для приложения Workout
2.3.2. Создание суперкласса
2.3.3. Недостатки подклассов
2.3.4. Рефакторинг модели данных с помощью перечислений
31
31
33
34
34
35
35
36
36
37
38
38
2.2.1. Полиморфизм на этапе компиляции
2.3. Перечисления вместо создания подклассов
41
43
44
44
46
47
48
48
49
Стр.6
6 Содержание
2.3.5. Подклассы или перечисления – что выбрать
2.3.6. Упражнения
2.4. Алгебраические типы данных
2.4.1. Типы-суммы
2.4.2. Типы-произведения
2.4.3. Распределение суммы в перечислении
2.4.4. Упражнение
2.5. Более безопасное использование строк
2.5.1. Опасность необработанных значений
2.5.2. Сопоставление для строк
2.5.3. Упражнения
2.6. В заключение
Глава 3. Написание более чистых свойств
3.1. Вычисляемые свойства
3.1.1. Моделирование упражнения
3.1.2. Преобразование функций в вычисляемые свойства
3.1.3. Завершение
3.2. Ленивые свойства
3.2.1. Создание учебного плана
3.2.2. Когда вычисляемые свойства не помогают
3.2.3. Использование ленивых свойств
3.2.4. Делаем ленивое свойство устойчивым
3.2.5. Изменяемые и ленивые свойства
3.2.6. Упражнения
3.3. Наблюдатели свойств
3.3.1. Обрезка пробелов
3.3.2. Запуск наблюдателей свойств из инициализаторов
3.3.3. Упражнения
3.4. В заключение
Глава 4. Делаем опционалы второй натурой
4.1. Назначение опционалов
4.2. Чистое извлечение значений
4.2.1. Сопоставление для опционалов
4.2.2. Методы извлечения
4.2.3. Когда значение вас не интересует
4.3. Сокрытие переменной
4.3.1. Реализация протокола CustomStringConvertible
4.4. Когда опционалы запрещены
4.4.1. Добавление вычисляемого свойства
4.5. Возврат опциональных строк
4.6. Детальный контроль над опционалами
4.6.1. Упражнения
4.7. Откат назад, если опционал равен nil
4.8. Упрощение опциональных перечислений
4.8.1. Упражнение
51
51
51
52
53
53
55
56
57
59
62
62
66
66
67
68
70
70
70
71
73
74
75
77
79
79
81
82
83
87
88
89
90
91
92
93
93
94
95
96
98
99
99
99
101
Стр.7
4.9. Цепочки опционалов
4.10. Ограничение опциональных логических типов
4.10.1. Сокращение логического типа до двух состояний
4.10.2. Откат к значению true
4.10.3. Логический тип данных с тремя состояниями
4.10.4. Реализация протокола RawRepresentable
4.10.5. Упражнение
4.11. Рекомендации по принудительному извлечению значения
4.11.1. Когда принудительное извлечение значения является «приемлемым»
4.11.2. Аварийный сбой со стилем
4.12. Приручаем неявно извлекаемые опционалы
4.12.1. Как распознать неявно извлекаемый опционал
4.12.2. Неявно извлекаемые опционалы на практике
4.12.3. Упражнение
4.13. В заключение
Глава 5. Разбираемся с инициализаторами
5.1. Правила инициализаторов структуры
5.1.1. Пользовательские инициализаторы
5.1.2. Странность инициализатора структуры
5.1.3. Упражнения
5.2. Инициализаторы и подклассы
5.2.1. Создание суперкласса настольной игры
5.2.2. Инициализаторы BoardGame
5.2.3. Создание подкласса
5.2.4. Потеря вспомогательных инициализаторов
5.2.5. Возвращение инициализаторов суперкласса
5.2.6. Упражнение
5.3. Минимизация инициализаторов класса
5.3.2. Деление подкласса на подклассы
5.3.3. Упражнение
5.4. Требуемые инициализаторы
5.4.1. Фабричные методы
5.4.2. Протоколы
5.4.3. Когда классы являются финальными
5.4.4. Упражнения
5.5. В заключение
Глава 6. Непринужденная обработка ошибок
6.1. Ошибки в Swift
6.1.1. Протокол Error
6.1.2. Генерация ошибок
6.1.3. Swift не показывает ошибки
6.1.4. Сохранение среды в предсказуемом состоянии
5.3.1. Реализация назначенного инициализатора в качестве
вспомогательного с использованием ключевого слова override
Содержание 7
102
103
104
104
105
106
107
108
109
109
110
111
111
114
114
117
117
118
120
121
121
122
123
125
126
127
129
130
130
132
133
134
134
136
137
138
138
142
143
144
144
145
147
Стр.8
8 Содержание
6.1.5. Упражнения
6.2. Распространение ошибок и перехват
6.2.1. Распространение ошибок
6.2.2. Добавление технических деталей для устранения неполадок
6.2.3. Централизация обработки ошибок
6.2.4. Упражнения
6.3. Создание симпатичных API
6.3.1. Сбор достоверных данных в типе
6.3.2. Ключевое слово try?
6.3.3. Ключевое слово try!
6.3.4. Возвращение опционалов
6.3.5. Упражнение
6.4. В заключение
Глава 7. Обобщения
7.1. Преимущества обобщений
7.1.1. Создание обобщенной функции
7.1.2. Рассмотрение обобщений
7.1.3. Упражнение
7.2. Ограничение обобщений
7.2.1. Нужна функция ограничения
7.2.2. Протоколы Equatable и Comparable
7.2.3. Ограничивать значит специализировать
7.2.4. Реализация протокола Comparable
7.2.5. Ограничение в сравнении с гибкостью
7.3. Ряд ограничений
7.3.1. Протокол Hashable
7.3.2. Комбинируем ограничения
7.3.3. Упражнения
7.4. Создание обобщенного типа
7.4.1. Желание совместить два типа, соответствующих протоколу Hashable
7.4.2. Создание типа Pair
7.4.3. Несколько обобщений
7.4.4. Соответствие протоколу Hashable
7.4.5. Упражнение
7.5. Обобщения и подтипы
7.5.1. Подтипы и инвариантность
7.5.2. Инвариантность в Swift
7.5.3. Универсальные типы Swift получают особые привилегии
7.6. В заключение
Глава 8. Становимся профессионалами в протокольно-ориентированном
программировании
8.1. Время выполнения в сравнении со временем компиляции
8.1.1. Создание протокола
8.1.2. Обобщения в сравнении с протоколами
150
151
151
154
158
160
161
161
163
164
164
165
165
168
169
170
172
174
174
175
176
177
178
179
179
180
181
182
182
183
183
184
185
187
187
188
189
190
191
194
195
195
196
Стр.9
8.1.3. Находим компромисс
Содержание 9
197
8.1.4. Переход ко времени выполнения
8.1.5. Выбор между временем компиляции и временем выполнения
8.1.6. Когда обобщение – лучший вариант
8.1.7. Упражнения
8.2. Зачем нужны ассоциированные типы
8.2.1. Недостатки протоколов
8.2.2. Попытка превратить все в протокол
8.2.3. Разработка обобщенного протокола
8.2.4. Моделирование протокола с ассоциированными типами
8.2.5. Реализация протокола с ассоциированными типами
8.2.6. Протоколы с ассоциированными типами в стандартной библиотеке
8.2.7. Другие случаи использования ассоциированных типов
8.2.8. Упражнение
8.3. Передача протокола с ассоциированными типами
8.3.1. Использование оператора where с ассоциированными типами
8.3.2. Типы, ограничивающие ассоциированные типы
8.3.3. Очистка API и наследование протокола
8.3.4. Упражнения
8.4. В заключение
Глава 9. Итераторы, последовательности и коллекции
9.1. Итерация
9.1.1. Циклы и метод makelterator
9.1.2. IteratorProtocol
9.1.3. Протокол Sequence
9.1.4. Посмотрим поближе
9.2. Сила Sequence
9.2.1. Метод filter
9.2.2. Метод forEach
9.23. Метод enumerated
9.2.4. Ленивая итерация
9.2.5. Метод reduce
9.2.6. Метод reduce into
9.2.7. Метод zip
9.2.8. Упражнения
9.3. Создание обобщенной структуры данных с помощью Sequence
9.3.1. Bag в действии
9.3.2. Создаем BagIterator
9.3.3. Реализация AnyIterator
9.3.4. Реализация ExpressibleByArrayLiteral
9.3.5. Упражнение
9.4. Протокол Collection
9.4.1. Ландшафт Collection
9.4.2. MutableCollection
198
199
200
201
202
203
204
205
206
207
209
209
210
211
212
213
215
216
217
221
222
222
223
224
224
226
226
226
227
228
229
230
232
233
233
233
236
238
239
240
241
242
242
Стр.10
10 Содержание
9.4.3. RangeReplaceableCollection
9.4.4. BidirectionalCollection
9.4.5. RandomAccessCollection
9.5. Создание коллекции
9.5.1. Создание плана поездки
9.5.2. Реализация Collection
9.5.3. Пользовательские сабскрипты
9.5.4. ExpressibleByDictionaryLiteral
9.5.5. Упражнение
9.6. В заключение
Глава 10. map, flatMap и compactMap
10.1. Знакомство с map
10.2. Последовательности
10.2.1. Упражнение
10.3. Использование метода map для опционалов
10.3.1. Когда использовать метод map с опционалами
10.3.2. Создание обложки
10.3.3. Более короткий вариант нотации
10.3.4. Упражнение
10.4. map – это абстракция
10.5. Овладеваем методом flatMap
10.5.1. В чем преимущества flatMap?
10.5.2. Когда метод map не подходит
10.5.3. Борьба с пирамидой гибели
10.5.4. Использование метода flatMap с опционалом
10.6. flatMap и коллекции
10.6.1. flatMap и строки
10.6.2. Сочетание flatMap и map
10.6.3. compactMap
10.6.4. Вложенность или цепочки
10.6.5. Упражнения
10.7. В заключение
Глава 11. Асинхронная обработка ошибок с помощью типа Result
11.1. Зачем использовать тип Result?
11.1.1. Как раздобыть Result
11.1.2. Result похож на Optional, но с изюминкой
11.1.3. Преимущества Result
11.1.4. Создание API с использованием типа Result
11.1.5. Из Cocoa Touch в Result
11.2. Распространение Result
11.2.1. Создание псевдонимов типов
10.1.1. Создание конвейера с помощью метода map
10.1.2. Использование метода map для словарей
10.1.3. Упражнения
244
245
245
246
247
248
249
250
251
252
255
256
258
260
261
262
263
263
264
265
267
269
269
270
270
271
273
275
279
280
281
282
283
285
285
290
291
292
293
294
295
297
299
299
Стр.11
11.2.2. Функция search
Содержание 11
300
11.3. Преобразование значений внутри Result
11.3.1. Упражнение
11.3.2. Использование метода flatMap для типа Result
11.3.3. Упражнения
11.4. Смешивание Result с функциями, генерирующими ошибку
11.4.1. От генерации ошибки к типу Result
11.4.2. Преобразование генерирующей функции внутри flatMap
11.4.3. Пропускаем ошибки через конвейер
11.4.4. Подходя к концу
11.4.5. Упражнение
11.5. Несколько ошибок внутри Result
11.5.1. Знакомство с AnyError
11.6. Невообразимый провал и Result
11.7. В заключение
Глава 12. Расширения протоколов
11.6.1. Когда протокол определяет Result
12.1. Наследование классов в сравнении с наследованием протоколов
12.1.1. Моделирование данных по горизонтали, а не по вертикали
12.1.2. Создание расширения протокола
12.1.3. Несколько расширений
12.2. Наследование в сравнении с композицией
12.2.1. Протокол Mailer
12.2.2. Наследование протокола
12.2.3. Композиционный подход
12.2.4. Высвобождаем энергию пересечения
12.2.5. Упражнение
12.3. Переопределение приоритетов
12.3.3. Упражнение
12.4. Расширение в двух направлениях
12.4.1. Выбор расширений
12.4.2. Упражнение
12.5. Расширение с использованием ассоциированных типов
12.5.1. Специализированное расширение
12.5.2. Недостаток расширения
12.6. Расширение с конкретными ограничениями
12.7. Расширение протокола Sequence
12.7.1. Заглянем внутрь метода filter
12.7.2. Создание метода take (while :)
12.7.3. Создание метода Inspect
12.7.4. Упражнение
12.8. В заключение
12.3.1. Переопределение реализации по умолчанию
12.3.2. Переопределение и наследование протоколов
302
304
304
306
307
307
309
310
312
312
313
313
316
316
319
325
326
327
328
329
330
330
331
332
334
336
336
336
337
338
339
339
341
341
343
344
344
346
346
348
350
351
352
Стр.12
12 Содержание
Глава 13. Шаблоны Swift
13.1. Внедрение зависимости
13.1.1. Замена реализации
354
355
355
13.1.2. Передача пользовательской версии Session
13.1.3. Ограничение ассоциированного типа
13.1.4. Замена реализации
13.1.5. Модульное тестирование и мокирование с использованием
ассоциированных типов
13.1.6. Использование типа Result
13.1.7. Упражнение
13.2. Условное соответствие
13.2.1. Бесплатная функциональность
13.2.2. Условное соответствие для ассоциированных типов
13.2.3. Делаем так, чтобы Array условно соответствовал
пользовательскому протоколу
13.2.4. Условное соответствие и обобщения
13.2.5. Условное соответствие для типов
13.2.6. Упражнение
13.3. Что делать с недостатками
13.4. Альтернатива протоколам
13.5. В заключение
Глава 14. Написание качественного кода на языке Swift
14.1. Документация по API
14.1.1. Как работает Quick Help
14.1.2. Добавление выносок в Quick Help
14.2. Комментарии
14.1.3. Документация в качестве HTML с использованием Jazzy
14.2.1. Объясняем причину
14.2.2. Объясняем только непонятные элементы
14.2.3. Код несет истину
14.2.4. Комментарии – не повязка для неудачных имен
14.2.5. Зомби-код
14.3. Правила стиля
14.3.1. Согласованность – это ключ
14.3.2. Обеспечение соблюдения правил с помощью линтера
14.3.3. Установка SwiftLint
14.3.4. Настройка SwiftLint
14.3.5. Временное отключение правил SwiftLint
14.3.6. Автозамена правил SwiftLint
13.3.1. Как избежать использования перечисления
13.3.2. Стирание типов
13.3.3. Упражнение
13.4.1. Чем мощнее, тем хуже код
13.4.2. Создание обобщенной структуры
13.4.3. Эмпирические правила полиморфизма
356
357
358
360
362
363
364
364
365
366
367
368
372
372
374
375
379
380
380
382
383
384
387
388
388
389
391
392
392
393
393
393
394
394
395
395
396
397
398
399
Стр.13
14.3.7. Синхронизация SwiftLint
14.4. Избавляемся от менеджеров
Содержание 13
399
14.4.1. Ценность менеджеров
14.4.2. Атака на менеджеров
14.4.3. Прокладываем дорогу для обобщений
14.5. Именование абстракций
14.5.1. Обобщенное или конкретное
14.5.2. Хорошие имена не меняются
14.5.3. Именование обобщений
14.6. Контрольный список
14.7. В заключение
Глава 15. Что дальше?
15.1. Создавайте фреймворки, предназначенные для Linux
15.2. Изучите диспетчер пакетов Swift
15.3. Изучайте фреймворки
15.4. Бросьте себе вызов
15.4.1. Присоединяйтесь к эволюции Swift
15.4.2. Заключительные слова
Предметный указатель
400
400
401
401
402
403
403
404
404
405
407
407
407
408
408
409
409
410
Стр.14