我试图在Measurement<UnitMass>和UnitMass上实现@AppStorage,以便用@AppStorage装饰器替换以下代码:
var unitOfMeasure: UnitMass {
get { AppSettings.defaults.string(forKey: "unitOfMeasure").flatMap { UnitMass.fromSymbol(rawValue: $0) }! }
set { AppSettings.defaults.set(newValue.symbol, forKey: "unitOfMeasure") }
}
var weightOverwrite: Measurement<UnitMass> {
get { .init(value: AppSettings.defaults.double(forKey: "weightOverwrite"), unit: unitOfMeasure) }
set { AppSettings.defaults.set(newValue.value, forKey: "weightOverwrite") }
}我该怎么做?我使用JSONEncoder/JSONDecoder实现了它:
extension Measurement: RawRepresentable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(Measurement.self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "{}"
}
return result
}
}但我不能为UnitMass做这件事:
extension UnitMass: RawRepresentable {
public init?(rawValue: String) {
for unitMass in UnitMass.allCases where rawValue == unitLength.symbol {
self = unitLength
}
return nil
}
}我得到了Designated initializer cannot be declared in an extension of 'UnitMass'。我做错了什么?
发布于 2021-04-24 03:13:00
这就是为什么您不能使UnitMass与RawRepresentable相一致的原因。
RawRepresentable有这样的要求:一致性类必须有一个init(rawValue:)初始化器。
UnitMass不是final,所以它可以有子类。
如果UnitMass与RawRepresentable一致,则UnitMass的子类也符合RawRepresentable,因此它们也必须具有init(rawValue:)。
如何实现子类中的init(rawValue:)?请注意,它们不能只继承UnitMass中的实现,因为子类可能有自己存储的属性,需要在初始化器中初始化。
因此,您的扩展需要UnitMass的所有子类来实现这个新的初始化器。好吧,扩展不应该添加需求-它们应该添加功能!
即使扩展可以做到这一点,对于您来说,访问UnitMass的每个子类并添加init(rawValue:):的实现也是不切实际的。)
总之,这里有一些解决办法:
使用包装类:
class MyUnitMass: RawRepresentable {
let unitMass: UnitMass
var rawValue: String {
unitMass.symbol
}
required init?(rawValue: String) {
// assuming fromSymbol actually uses the correct converter
unitMass = UnitMass.fromSymbol(rawValue: rawValue)
}
}或者,将UnitMass在UserDefaults中保存为Data而不是String,因为UnitMass符合NSSecureCoding。
let data = try NSKeyedArchiver.archivedData(withRootObject: UnitMass.grams, requiringSecureCoding: false)
// save "data" to UserDefaults instead
let unitMass = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! UnitMass这也具有编码converter的优点,而不必在fromSymbol中对其进行硬编码(想必您现在正在做的事情)。
还请注意,如果只将unitOfMeasure设置用作weightOverwrite的单元,则应该将weightOverwrite保存在用户默认值中,并按以下方式声明unitOfMeasure:
@AppStorage("hello", store: UserDefaults.standard)
var weightOverwrite: Measurement<UnitMass> = Measurement(value: 1, unit: .grams)
var unitOfMeasure: UnitMass {
get { weightOverwrite.unit }
set { weightOverwrite.convert(to: newValue) }
}发布于 2021-10-31 08:20:50
您可以扩展RawReprresentable本身,以便UnitMass自动开始执行它。
extension RawRepresentable where Self: NSSecureCoding {
var rawValue: String {
let data = try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
return data!.base64EncodedString()
}
init?(rawValue: String) {
if let data = Data(base64Encoded: rawValue), let unit = (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)) as? Self {
self = unit
} else {
return nil
}
}
}
extension UnitMass: RawRepresentable { }https://stackoverflow.com/questions/67238540
复制相似问题