我试图编码一个对象,但我遇到了一些麻烦。它对弦乐,布尔等都很好用,但我不知道怎么用它来演奏枚举。 我需要对此进行编码:
enum Creature: Equatable {
enum UnicornColor {
case yellow, pink, white
}
case unicorn(UnicornColor)
case crusty
case shark
case dragon
我使用此代码进行编码:
func saveFavCreature(creature: Dream.Creature) {
let filename = NSHomeDirectory().appending("/Documents/favCreature.bin")
NSKeyedArchiver.archiveRootObject(creature, toFile: filename)
}
func loadFavCreature() -> Dream.Creature {
let filename = NSHomeDirectory().appending("/Documents/favCreature.bin")
let unarchived = NSKeyedUnarchiver.unarchiveObject(withFile: filename)
return unarchived! as! Dream.Creature
}
这是必需的函数(model.favoriteCreature == Dream.Creature)
override func encode(with aCoder: NSCoder) {
aCoder.encode(model.favoriteCreature, forKey: "FavoriteCreature")
aCoder.encode(String(), forKey: "CreatureName")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let favoriteCreature = aDecoder.decodeObject(forKey: "FavoriteCreature")
let name = aDecoder.decodeObject(forKey: "CreatureName")
}
它与" name"一起工作正常,我认为问题出在aCoder.encode()中,因为我不知道在那里写什么类型。运行时出现下一个错误: - [_ SwiftValue encodeWithCoder:]:发送到实例的无法识别的选择器 - [NSKeyedArchiver dealloc]:警告:NSKeyedArchiver在没有调用-finishEncoding的情况下解除分配。
我在评论中阅读了一些建议,可以假设我在枚举生物中没有rawValues,我做了原始类型" String"在那个枚举中:
enum Creature: String, Equatable {
enum UnicornColor {
case yellow, pink, white
}
case unicorn(UnicornColor)
case crusty
case shark
case dragon
现在我有这个错误: 具有原始类型的枚举不能包含带参数的情况。 我还读到相关值和原始值不能共存。也许还有其他方法可以在没有原始值的情况下存档枚举?
希望有人可以帮助我,谢谢
答案 0 :(得分:2)
您正在处理出现的问题,因为Swift本机功能并不总能与Objective-C一起使用。 NSCoding
源于Objective-C世界,而Objective-C对Swift Enum一无所知,因此您不能简单地归档Enum。
通常,您可以使用原始值对枚举进行编码/解码,但正如您所发现的,您无法在Swift枚举中组合关联类型和原始值。
不幸的是,这意味着您需要构建自己的“原始”值方法并在Creature
枚举中明确处理这些案例:
enum Creature {
enum UnicornColor: Int {
case yellow = 0, pink, white
}
case unicorn(UnicornColor)
case crusty
case shark
case dragon
init?(_ creatureType: Int, color: Int? = nil) {
switch creatureType {
case 0:
guard let rawColor = color,
let unicornColor = Creature.UnicornColor(rawValue:rawColor) else {
return nil
}
self = .unicorn(unicornColor)
case 1:
self = .crusty
case 2:
self = .shark
case 3:
self = .dragon
default:
return nil
}
}
func toRawValues() -> (creatureType:Int, unicornColor:Int?) {
switch self {
case .unicorn(let color):
let rawColor = color.rawValue
return(0,rawColor)
case .crusty:
return (1,nil)
case .shark:
return (2,nil)
case .dragon:
return (3,nil)
}
}
}
然后您可以像这样编码/解码:
class SomeClass: NSObject, NSCoding {
var creature: Creature
init(_ creature: Creature) {
self.creature = creature
}
required init?(coder aDecoder: NSCoder) {
let creatureType = aDecoder.decodeInteger(forKey: "creatureType")
let unicornColor = aDecoder.decodeInteger(forKey: "unicornColor")
guard let creature = Creature(creatureType, color: unicornColor) else {
return nil
}
self.creature = creature
super.init()
}
func encode(with aCoder: NSCoder) {
let creatureValues = self.creature.toRawValues()
aCoder.encode(creatureValues.creatureType, forKey: "creatureType")
if let unicornColor = creatureValues.unicornColor {
aCoder.encode(unicornColor, forKey: "unicornColor")
}
}
}
测试给出:
let a = SomeClass(.unicorn(.pink))
var data = NSMutableData()
let coder = NSKeyedArchiver(forWritingWith: data)
a.encode(with: coder)
coder.finishEncoding()
let decoder = NSKeyedUnarchiver(forReadingWith: data as Data)
if let b = SomeClass(coder: decoder) {
print(b.creature)
}
麒麟(Creature.UnicornColor.pink)
就个人而言,我会使Creature
成为一个类并使用继承来处理独角兽和其他类型之间的差异
答案 1 :(得分:1)
您的问题的主要问题是您无法将Swift枚举传递给encode(_:forKey:)
。
This article将帮助您解决这一问题。如果枚举很容易rawValue
,那就不难了。
但是,正如您所见, 带有原始类型的枚举不能包含带参数的案例。
简单的枚举很容易就像这样rawValue
:
enum UnicornColor: Int {
case yellow, pink, white
}
但是具有关联值的枚举不能以这种方式拥有rawValue
。您可能需要自己管理。
例如,将内部枚举rawValue
设为Int
:
enum Creature: Equatable {
enum UnicornColor: Int {
case yellow, pink, white
}
case unicorn(UnicornColor)
case crusty
case shark
case dragon
static func == (lhs: Creature, rhs: Creature) -> Bool {
//...
}
}
您可以将Dream.Creature
的扩展名编写为:
extension Dream.Creature: RawRepresentable {
var rawValue: Int {
switch self {
case .unicorn(let color):
return 0x0001_0000 + color.rawValue
case .crusty:
return 0x0002_0000
case .shark:
return 0x0003_0000
case .dragon:
return 0x0004_0000
}
}
init?(rawValue: Int) {
switch rawValue {
case 0x0001_0000...0x0001_FFFF:
if let color = UnicornColor(rawValue: rawValue & 0xFFFF) {
self = .unicorn(color)
} else {
return nil
}
case 0x0002_0000:
self = .crusty
case 0x0003_0000:
self = .shark
case 0x0004_0000:
self = .dragon
default:
return nil
}
}
}
(事实上,它不是真正的rawValue
,您最好将其重命名为更合适的名称。)
使用上面显示的定义,您可以使用上面链接中显示的代码。
答案 2 :(得分:1)
为了简化编码/解码,您可以为需要Data
的Creature和名为data
的计算属性提供初始值设定项。随着Creature的更改或添加新的关联值,NSCoding
的界面不会更改。
class Foo: NSObject, NSCoding {
let creature: Creature
init(with creature: Creature = Creature.crusty) {
self.creature = creature
super.init()
}
required init?(coder aDecoder: NSCoder) {
guard let data = aDecoder.decodeObject(forKey: "creature") as? Data else { return nil }
guard let _creature = Creature(with: data) else { return nil }
self.creature = _creature
super.init()
}
func encode(with aCoder: NSCoder) {
aCoder.encode(creature.data, forKey: "creature")
}
}
生物进出Data
的序列化可以像这样完成。
enum Creature {
enum UnicornColor {
case yellow, pink, white
}
case unicorn(UnicornColor)
case crusty
case shark
case dragon
enum Index {
static fileprivate let ofEnum = 0 // data[0] holds enum value
static fileprivate let ofUnicornColor = 1 // data[1] holds unicorn color
}
init?(with data: Data) {
switch data[Index.ofEnum] {
case 1:
switch data[Index.ofUnicornColor] {
case 1: self = .unicorn(.yellow)
case 2: self = .unicorn(.pink)
case 3: self = .unicorn(.white)
default:
return nil
}
case 2: self = .crusty
case 3: self = .shark
case 4: self = .dragon
default:
return nil
}
}
var data: Data {
var data = Data(count: 2)
// the initializer above zero fills data, therefore serialize values starting at 1
switch self {
case .unicorn(let color):
data[Index.ofEnum] = 1
switch color {
case .yellow: data[Index.ofUnicornColor] = 1
case .pink: data[Index.ofUnicornColor] = 2
case .white: data[Index.ofUnicornColor] = 3
}
case .crusty: data[Index.ofEnum] = 2
case .shark: data[Index.ofEnum] = 3
case .dragon: data[Index.ofEnum] = 4
}
return data
}
}