Как перебрать все значения enum с типом String в Swift?
Решение: используйте протокол CaseIterable
В Swift 5.9 и Xcode 15 ваша проблема решается очень просто — нужно добавить протокол CaseIterable к вашему перечислению. Давайте разберем правильный синтаксис:
enum WeekDay: String, CaseIterable {
case monday = "Понедельник"
case tuesday = "Вторник"
case wednesday = "Среда"
case thursday = "Четверг"
case friday = "Пятница"
case saturday = "Суббота"
case sunday = "Воскресенье"
}
// Теперь можно перебрать все значения:
for day in WeekDay.allCases {
print(day.rawValue) // Выведет: Понедельник, Вторник...
}
После добавления CaseIterable у перечисления автоматически появляется статическое свойство allCases, которое возвращает массив всех кейсов в порядке их объявления.
Почему это работает?
CaseIterable— это протокол из стандартной библиотеки Swift, который автоматически генерирует коллекцию всех кейсов для перечислений без associated values.- Ваше перечисление имеет raw values (String), но это не мешает протоколу работать — он просто собирает сами кейсы, а их значения можно получить через свойство
rawValue. - Протокол доступен начиная с Swift 4.2 (Xcode 10+).
Практический пример: отображение в TableView
class DaysViewController: UITableViewController {
let days = WeekDay.allCases
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return days.count // 7
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DayCell", for: indexPath)
let day = days[indexPath.row]
cell.textLabel?.text = day.rawValue // "Понедельник" и т.д.
return cell
}
}
Дополнительные возможности
Вы также можете получить индекс кейса, если нужно:
if let index = WeekDay.allCases.firstIndex(of: .friday) {
print("Пятница под индексом \(index)") // 4
}
Или создать словарь для быстрого доступа:
let dayDict = Dictionary(uniqueKeysWithValues: WeekDay.allCases.map { ($0.rawValue, $0) })
print(dayDict["Среда"] == .wednesday) // true
Важно: Если вы используете Xcode 10 и выше, этот подход работает без каких-либо дополнительных настроек. В более старых версиях Swift придется использовать ручную реализацию (см. альтернативный ответ).
<<Альтернатива: ручная реализация для старых версий Swift
Если по какой-то причине вы не можете использовать CaseIterable (например, проект на Swift 4.1 или ниже), можно добавить статический массив вручную:
enum WeekDay: String {
case monday = "Понедельник"
case tuesday = "Вторник"
case wednesday = "Среда"
case thursday = "Четверг"
case friday = "Пятница"
case saturday = "Суббота"
case sunday = "Воскресенье"
static var allCases: [WeekDay] {
return [.monday, .tuesday, .wednesday, .thursday, .friday, .saturday, .sunday]
}
}
// Использование:
for day in WeekDay.allCases {
print(day.rawValue)
}
Минус такого подхода — если вы добавите новый кейс, нужно не забыть обновить массив вручную. Поэтому для современных проектов всегда предпочтительнее использовать CaseIterable.
Также можно использовать рефлексию через Mirror, но это излишне усложнит код и снизит производительность — такой вариант не рекомендуется.