Reputation: 213
I have this enum:
enum DMED: String {
case money = "DMMoney"
case netWorth = "DMNetWorth"
case businessNum = "DMBusinessNum"
case generalEPM = "DMGeneralEPM"
case generalThreat = "DMGeneralThreat"
}
And in a class I have, I have this decoder function:
required init?(coder aDecoder: NSCoder) {
self.money = (aDecoder.decodeDouble(forKey: DMED.money.rawValue))
self.netWorth = (aDecoder.decodeDouble(forKey: DMED.netWorth.rawValue))
self.businessNum = (aDecoder.decodeInteger(forKey: DMED.businessNum.rawValue))
self.generalEPM = (aDecoder.decodeInteger(forKey: DMED.generalEPM.rawValue))
self.generalThreat = (aDecoder.decodeInteger(forKey: DMED.generalThreat.rawValue))
}
I would love to know if it would be possible to remove the .rawValue from all of the enum calls. Thanks for your help in advanced.
Upvotes: 0
Views: 3565
Reputation: 80781
One option would be to write a wrapper that allows for typed-key coding:
struct KeyedNSCoder<Key : CodingKey> {
let coder: NSCoder
init(_ coder: NSCoder, keyedBy _: Key.Type) {
self.coder = coder
}
func decodeDouble(forKey key: Key) -> Double {
return coder.decodeDouble(forKey: key.stringValue)
}
func decodeInteger(forKey key: Key) -> Int {
return coder.decodeInteger(forKey: key.stringValue)
}
// repeat for other coding methods...
}
Then you can simply say:
enum DMED : String, CodingKey {
case money = "DMMoney"
case netWorth = "DMNetWorth"
case businessNum = "DMBusinessNum"
case generalEPM = "DMGeneralEPM"
case generalThreat = "DMGeneralThreat"
}
class C : NSCoding {
var money: Double // note: do not represent monetary values with floating-point numbers
var netWorth: Double
var businessNum: Int
var generalEPM: Int
var generalThreat: Int
required init?(coder aDecoder: NSCoder) {
let decoder = KeyedNSCoder(aDecoder, keyedBy: DMED.self)
self.money = decoder.decodeDouble(forKey: .money)
self.netWorth = decoder.decodeDouble(forKey: .netWorth)
self.businessNum = decoder.decodeInteger(forKey: .businessNum)
self.generalEPM = decoder.decodeInteger(forKey: .generalEPM)
self.generalThreat = decoder.decodeInteger(forKey: .generalThreat)
}
func encode(with coder: NSCoder) {
// ...
}
}
Upvotes: 0
Reputation: 32775
You could add an extension over NSCoder
to handle the DMED
keys:
extension NSCoder {
func decodeDouble(forKey key: DMED) -> Double {
return decodeDouble(forKey: key.rawValue)
}
func decodeInteger(forKey key: DMED) -> Int {
return decodeInteger(forKey: key.rawValue)
}
}
self.money = aDecoder.decodeDouble(forKey: .money)
Or, if you want to make the methods more general, and work with any String enums, you could make the method overrides generic:
extension NSCoder {
func decodeDouble<R: RawRepresentable>(forKey key: R) -> Double where R.RawValue == String {
return decodeDouble(forKey: key.rawValue)
}
func decodeInteger<R: RawRepresentable>(forKey key: R) -> Int where R.RawValue == String {
return decodeInteger(forKey: key.rawValue)
}
}
self.money = aDecoder.decodeDouble(forKey: DMED.money)
Or, making use of the type inference support, you can declare an even more generic method:
extension NSCoder {
func decode<R: RawRepresentable>(forKey key: R) -> Double where R.RawValue == String {
return decodeDouble(forKey: key.rawValue)
}
func decode<R: RawRepresentable>(forKey key: R) -> Int where R.RawValue == String {
return decodeInteger(forKey: key.rawValue)
}
func decode<R: RawRepresentable>(forKey key: R) -> Any? where R.RawValue == String {
return decodeObject(forKey: key.rawValue)
}
}
required init?(coder aDecoder: NSCoder) {
self.money = aDecoder.decode(forKey: DMED.money)
self.netWorth = aDecoder.decode(forKey: DMED.netWorth)
self.businessNum = aDecoder.decode(forKey: DMED.businessNum)
self.generalEPM = aDecoder.decode(forKey: DMED.generalEPM)
self.generalThreat = aDecoder.decode(forKey: DMED.generalThreat)
}
Upvotes: 1
Reputation: 318774
If your only use of the enum
values is so they can be used as String
constants, you should change your code to use a struct
with static
values.
struct DMED {
static let money = "DMMoney"
static let netWorth = "DMNetWorth"
static let businessNum = "DMBusinessNum"
static let generalEPM = "DMGeneralEPM"
static let generalThreat = "DMGeneralThreat"
}
required init?(coder aDecoder: NSCoder) {
self.money = (aDecoder.decodeDouble(forKey: DMED.money))
self.netWorth = (aDecoder.decodeDouble(forKey: DMED.netWorth))
self.businessNum = (aDecoder.decodeInteger(forKey: DMED.businessNum))
self.generalEPM = (aDecoder.decodeInteger(forKey: DMED.generalEPM))
self.generalThreat = (aDecoder.decodeInteger(forKey: DMED.generalThreat))
}
Upvotes: 1