В моем проекте у меня есть пара перечислений, которые я использую везде, эти перечисления создаются на основе внешнего json, поэтому ввод всегда необязателен.Если перечисление не может быть создано из входных данных, я определю значение по умолчанию.
Пример того, как я делаю вещи сейчас:
enum TextAlign:String {
case left, center, right
}
let rawData = [String:Any]()
func getTextAlign() -> TextAlign {
if let rawTextAlignString = rawData["textAlign"] as? String, let align = TextAlign(rawValue: rawTextAlignString) {
return align
}
return TextAlign.left
}
let textAlign = self.getTextAlign()
Это работает, очевидно, но я быхотел бы сделать мой конструктор немного более быстрым, универсальным и применимым к большему количеству этих перечислений.Моя цель состоит в том, чтобы создать эти перечисления следующим образом:
let textAlign = TextAlign(rawOptionalValue: rawData["textAlign"] as? String) ?? TextAlign.left
Итак, я в основном хочу отказавшийся инициализатор, который я могу просто написать для перечисления TextAlign, но должен быть способ объявить это более«универсальный» способ, чтобы я мог использовать инициализатор во всех моих экземплярах enum: String.Я немного борюсь с синтаксисом и опциями обобщений в swift.
Любая идея?
Обновление # 1
Я вижу много ответов, которые не всенеправильно, но, вероятно, я не достаточно ясно понял, что я ищу.
У меня есть несколько перечислений, подобных этому:
enum TextAlign:String {
case left, center, right
}
enum CornerRadius:String {
case none, medium, large
}
enum Spacing:String {
case tight, medium, loose
}
Я хотел бы определить только одну функцию, которая можетинициализировать все эти перечисления.(не потому, что я ленивый, а потому, что я хочу понять, как использовать Generics для этого)
Вероятно, мне нужен статический функционал в расширении, которое применяется ко всем этим перечислениям String / RawRepresentable.Я не хочу писать все эти неудачные инициализаторы для каждого перечисления.(Я полагаю, что это возможно, но я не могу понять синтаксис)
Обновление # 2
Немного поиграв с ответом Джоакима, я нашел следующее решение:
extension RawRepresentable {
static func create<T:Any>(_ value: Any?, defaultValue: Self) -> Self where Self.RawValue == T {
guard let rawValue = value as? T, let instance = Self.init(rawValue: rawValue) else {
return defaultValue
}
return instance
}
}
Это позволяет мне создавать экземпляры перечислений типа String
и Int
(и более) с помощью этой функции.Вот так:
enum TextAlign:String {
case left, center, right
}
enum CornerRadius:Int {
case none, medium, large
}
let json:[String:Any] = [
"textAlign":"left",
"cornerRadius":0
]
let cornerRadius = CornerRadius.create(json["cornerRadius"], defaultValue: .medium)
let align = TextAlign.create(json["textAlign"], defaultValue: .center)
Мне нравится, что я могу просто указать Any?
в качестве аргумента и что он сам выполняет кастинг, выполняя let rawValue = value as? T
.
Update #3 (решение)
Хорошо, сложность всего этого все еще немного беспокоила меня, поэтому я попробовал маршрут init, который, по моему мнению, выглядит чище.Теперь все выглядит так:
extension RawRepresentable {
init(from value: Any?, or defaultValue: Self) {
self = Self.init(from: value) ?? defaultValue
}
init?(from value: Any?) {
guard let rawValue = value as? Self.RawValue, let instance = Self.init(rawValue: rawValue) else {
return nil
}
self = instance
}
}
Я создал неудачный и не сбойный init со значением по умолчанию для удобства.
Теперь я могу просто создать экземпляр любого перечисления, подобного этому:
let cornerRadius = CornerRadius(json["cornerRadius"], or: .medium)
// or an optional one
let align = TextAlign(json["textAlign"])
Теперь я закончил с обновлениями ...