Ответ
Да, в Swift оператор switch должен быть исчерпывающим (exhaustive) при работе с перечислениями (enum). Компилятор проверяет это и выдает ошибку, если не все кейсы обработаны.
Правила и исключения:
-
Обычный enum: Необходимо явно перечислить все кейсы или добавить ветку
default.enum Direction { case north, south, east, west } let dir = Direction.north switch dir { case .north: print("North") case .south: print("South") case .east: print("East") case .west: print("West") // default не требуется, все кейсы обработаны } -
@unknown default: Используется дляenum, помеченных как@frozen(или стандартных библиотечных), которые не будут меняться в будущем, и для незамороженных (non-frozen) enum из фреймворков, которые могут получить новые кейсы в следующих версиях OS. Эта ветка обрабатывает любые потенциальные будущие кейсы, не нарушая исчерпывающую проверку компилятора.// Для non-frozen enum из фреймворка (например, UITableViewCell.CellStyle) switch cellStyle { case .default: // Обработка известных кейсов case .value1: case .value2: @unknown default: // Обрабатывает любые новые кейсы, добавленные в будущем break }
Почему это важно: Эта гарантия полноты обработки на этапе компиляции исключает целый класс ошибок времени выполнения, связанных с неучтенными состояниями данных.
Ответ 18+ 🔞
О, смотри-ка, какой у нас тут академический вопрос подъехал! Swift и его switch, который как будто занудный препод в универе: «А ты все кейсы перечислил? А ну-ка покажи!»
Так вот, слушай сюда, этот ваш оператор switch — он реально исчерпывающий должен быть, когда дело доходит до enum. Компилятор, сука, стоит над душой как злой участковый и проверяет: «А все ли случаи, пидорок, обработал?» Не обработал — получай ошибку и иди нахуй переделывать.
Как это работает, а главное — когда оно ломается:
-
Обычный
enum, домашний, ручной работы: Тут всё просто, как три копейки. Либо ты вswitchперечисляешь ВСЕ возможные варианты, либо, если тебе лень и ты распиздяй, пишешьdefault— и компилятор отстаёт.enum Direction { case north, south, east, west // Четыре стороны, и ни хуя больше } let dir = Direction.north switch dir { case .north: print("На север, епта!") case .south: print("На юг, блядь") case .east: print("На восток") case .west: print("На запад") // default тут не нужен, потому что мы и так всё перебрали. Компилятор доволен. } -
А вот тут начинается магия, блядь —
@unknown default: Это, сука, специальная штука дляenum'ов, которые живут не в твоём коде. Бывают они двух видов:@frozen(замороженные) — это те, которые больше меняться не будут. Их из стандартной библиотеки.non-frozen(незамороженные) — это те, которые живут в чужих фреймворках (например, от Apple). И какая-нибудь новая версия iOS может прийти и сказать: «А мы тут новый кейсик добавили, получайте!»
Вот чтобы твой код не сломался в хлам, когда такое произойдёт, и нужен
@unknown default. Он как страховка от ебучего сюрприза. Ты обрабатываешь все известные на сейчас кейсы, а на будущее говоришь: «Ладно, на всё остальное — похуй, просто пропусти».// Допустим, это какой-то стиль ячейки из UIKit (он non-frozen) switch cellStyle { case .default: // Обрабатываем то, что знаем case .value1: case .value2: @unknown default: // А это — затычка на случай, если Apple в будущем подкинет ещё какой-нибудь .value3Supreme break // Идём нахуй и ничего не делаем, но хотя бы не падаем! }
А зачем весь этот цирк, спросишь? А затем, чувак, чтобы у тебя в продакшене не вылезла ошибка на ровном месте, потому что ты какой-то кейс хуй забыл. Компилятор заставляет тебя думать головой на этапе написания кода, а не когда пользователи уже тебе в личку пишут: «Приложение, блядь, сломалось!». Это, можно сказать, защита от самого себя, от своей же распиздяйскости.