Как перебрать все значения enum с типом String в Swift?
Решение: используем протокол CaseIterable
В Swift для перебора всех значений enum существует специальный протокол — CaseIterable. Он автоматически генерирует свойство allCases, которое возвращает массив всех case'ов перечисления в порядке их объявления.
Вот как это работает с вашим примером:
enum Category: String, CaseIterable {
case electronics = "Электроника"
case clothing = "Одежда"
case books = "Книги"
case sports = "Спорт"
}
// Теперь можно перебрать все значения
for category in Category.allCases {
print("Case: \(category), rawValue: \(category.rawValue)")
}
// Вывод:
// Case: electronics, rawValue: Электроника
// Case: clothing, rawValue: Одежда
// Case: books, rawValue: Книги
// Case: sports, rawValue: Спорт
Что важно знать:
- CaseIterable — это протокол, который нужно явно указать при объявлении enum
- allCases — автоматически сгенерированное свойство, возвращающее массив всех case'ов
- Порядок элементов в
allCasesсоответствует порядку объявления case'ов в коде - Протокол работает с любым типом rawValue (String, Int, Float и т.д.)
Практический пример для picker'а:
import UIKit
enum Category: String, CaseIterable {
case electronics = "Электроника"
case clothing = "Одежда"
case books = "Книги"
case sports = "Спорт"
}
class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
let pickerView = UIPickerView()
override func viewDidLoad() {
super.viewDidLoad()
pickerView.dataSource = self
pickerView.delegate = self
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return Category.allCases.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return Category.allCases[row].rawValue
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let selectedCategory = Category.allCases[row]
print("Выбрана категория: \(selectedCategory.rawValue)")
}
}
Дополнительные возможности:
Вы можете получить не только rawValue, но и сам case для дальнейшей работы:
// Фильтрация категорий
let electronicCategories = Category.allCases.filter { $0 == .electronics }
// Поиск по rawValue
if let category = Category(rawValue: "Одежда") {
print("Найдена категория: \(category)")
}
// Создание массива строк для UI
let categoryNames = Category.allCases.map { $0.rawValue }
print(categoryNames) // ["Электроника", "Одежда", "Книги", "Спорт"]
Важно помнить: если ваш enum имеет связанные значения (associated values), то CaseIterable не сработает автоматически — вам придётся реализовать allCases вручную. Но для простых перечислений с rawValue это идеальное решение.
Альтернативный подход: ручная реализация allCases
Если по каким-то причинам вы не хотите использовать CaseIterable (например, для версий Swift ниже 4.2 или для enum с associated values), можно реализовать свойство allCases вручную:
enum Category: String {
case electronics = "Электроника"
case clothing = "Одежда"
case books = "Книги"
case sports = "Спорт"
static var allCases: [Category] {
return [.electronics, .clothing, .books, .sports]
}
}
// Использование:
for category in Category.allCases {
print(category.rawValue)
}
Когда это может пригодиться:
- Вы поддерживаете старую версию Swift (до 4.2)
- Нужно исключить некоторые case'ы из перебора
- Enum содержит associated values, и автоматическая генерация невозможна
- Хотите изменить порядок элементов в переборе
Недостаток этого подхода — при добавлении нового case в enum нужно не забыть обновить свойство allCases вручную. В остальном он работает так же, как и автоматическая версия.
Ответов пока нет.
Войдите чтобы оставить ответ