#swift #enums #property-wrapper
#swift #перечисления #свойство-оболочка
Вопрос:
Приведенная ниже структура будет работать для примитивных типов данных, таких как Int
, String
, Double
, и т.д., Есть ли способ заставить это работать для перечислений, чтобы мне не приходилось использовать rawValues для разбора вручную?
@propertyWrapper
struct Storage<T> {
let objectName: String
let defaultValue: T
let defaults: UserDefaults
init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
self.objectName = objectName
self.defaultValue = defaultValue
self.defaults = defaults
}
var wrappedValue: T {
get { return self.defaults.object(forKey: self.objectName) as? T ?? self.defaultValue }
set { self.defaults.set(newValue, forKey: self.objectName) }
}
}
В настоящее время мой обходной путь заключается в том, чтобы обернуть объект в другой метод получения и установки для перечисления следующим образом.
enum SomeType: String {
case foo, bar, baz
}
class Defaults {
@Storage("object", default: "")
private var: objectContainer: String
var object: SomeType? {
get {
return SomeType(rawValue: self.objectContainer)
}
set {
self.objectContainer = newValue.rawValue ?? ""
}
}
}
Я попытался создать другую оболочку свойств, специфичную для RawRepresentable
типов, но Swift не может определить тип T
из этого.
@propertyWrapper
struct RawRepresentableStorage<T: RawRepresentable> {
let objectName: String
let defaultValue: T
let defaults: UserDefaults
init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
self.objectName = objectName
self.defaultValue = defaultValue
self.defaults = defaults
}
var wrappedValue: T {
get {
guard let object = self.defaults.object(forKey: self.objectName) as? T else {
return self.defaultValue
}
// Error on this line:
// `Cannot convert value of type 'T' to expected argument type 'T.RawValue'`
return T(rawValue: object) ?? self.defaultValue
}
set {
self.defaults.set(newValue.rawValue, forKey: self.objectName)
}
}
}
Также было бы не идеально создавать типы оболочек для каждого сохраняемого перечисления в базе кода, даже если их всего несколько
Есть ли что-то, чего мне не хватает, или это текущее ограничение Swift?
Ответ №1:
В вашем wrappedValue
получателе вы приводите к неправильному типу. Вы переходите object
к T(rawValue:)
, поэтому его тип должен быть T.RawValue
, а не T
.
@propertyWrapper
struct RawRepresentableStorage<T: RawRepresentable> {
let objectName: String
let defaultValue: T
let defaults: UserDefaults
init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
self.objectName = objectName
self.defaultValue = defaultValue
self.defaults = defaults
}
var wrappedValue: T {
get {
guard let object = self.defaults.object(forKey: self.objectName) as? T.RawValue else {
return self.defaultValue
}
return T(rawValue: object) ?? self.defaultValue
}
set {
self.defaults.set(newValue.rawValue, forKey: self.objectName)
}
}
}
Комментарии:
1. Ах да, но все
T(rawValue: object)
равно не будет компилироваться, потому что компилятор не знает общий типT
. Я бы увидел это, если бы запустил код, но спасибо за предупреждение.2. @ZonilyJame код в моем ответе компилируется просто отлично, я протестировал его на игровой площадке. Компилятор может вывести тип
T
из объявления свойства, которое вы аннотируете@RawRepresentableStorage
. Какую ошибку компилятора вы получаете? И как вы используете оболочку свойств, которая выдает указанную ошибку?