如何在 Swift 3 中使用 NSCoder 对 [Character : Int] 属性 进行编码?
How do I encode [Character : Int] property using NSCoder in Swift 3?
import UIKit
class Foo: NSObject, NSCoding {
var cx: [Character : Int]
init(cx: [Character : Int]) {
self.cx = cx
}
// MARK: - <NSCoding>
required convenience init(coder aDecoder: NSCoder) {
let cx = aDecoder.decodeObject(forKey: "cxKey") as! [Character : Int]
self.init(cx: cx)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(cx, forKey: "cxKey")
}
}
呼叫:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var foo = Foo(cx: ["C": 5, "X": 6])
let encodedData = NSKeyedArchiver.archivedData(withRootObject: foo)
print("encodedData: \(encodedData))")
if let foo1 = NSKeyedUnarchiver.unarchiveObject(with: encodedData) as? Foo {
print("cx = ", foo1.cx)
} else{
print("There is an issue")
}
}
}
Xcode 抛出错误:*** 由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序,原因:'-[_SwiftValue encodeWithCoder:]: 无法识别的选择器发送到实例
原因
这是因为 cx
中的 Character
类型的键将被装箱为 _SwiftValue
对象,这些对象将被发送 encodeWithCoder:
导致无法识别的选择器异常。
请参阅 SwiftValue.h 顶部的评论:
This implements the Objective-C class that is used to carry Swift
values that have been bridged to Objective-C objects without special
handling. The class is opaque to user code, but is NSObject
- and
NSCopying
- conforming and is understood by the Swift runtime for
dynamic casting back to the contained type.
解决方案
如果您可以将 cx
的类型更改为 [String : Int]
,一切都会开箱即用(无双关语)。
否则,您必须在解码初始化程序中将 Foo.encode(with:)
中的 cx
转换为可以编码的内容(例如 [String : Int]
,反之亦然)。
请参阅 and How do I encode enum using NSCoder in swift? 了解一些代码。
import UIKit
class Foo: NSObject, NSCoding {
var cx: [Character : Int]
init(cx: [Character : Int]) {
self.cx = cx
}
// MARK: - <NSCoding>
required convenience init(coder aDecoder: NSCoder) {
let cx = aDecoder.decodeObject(forKey: "cxKey") as! [Character : Int]
self.init(cx: cx)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(cx, forKey: "cxKey")
}
}
呼叫:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var foo = Foo(cx: ["C": 5, "X": 6])
let encodedData = NSKeyedArchiver.archivedData(withRootObject: foo)
print("encodedData: \(encodedData))")
if let foo1 = NSKeyedUnarchiver.unarchiveObject(with: encodedData) as? Foo {
print("cx = ", foo1.cx)
} else{
print("There is an issue")
}
}
}
Xcode 抛出错误:*** 由于未捕获的异常 'NSInvalidArgumentException' 而终止应用程序,原因:'-[_SwiftValue encodeWithCoder:]: 无法识别的选择器发送到实例
原因
这是因为 cx
中的 Character
类型的键将被装箱为 _SwiftValue
对象,这些对象将被发送 encodeWithCoder:
导致无法识别的选择器异常。
请参阅 SwiftValue.h 顶部的评论:
This implements the Objective-C class that is used to carry Swift values that have been bridged to Objective-C objects without special handling. The class is opaque to user code, but is
NSObject
- andNSCopying
- conforming and is understood by the Swift runtime for dynamic casting back to the contained type.
解决方案
如果您可以将 cx
的类型更改为 [String : Int]
,一切都会开箱即用(无双关语)。
否则,您必须在解码初始化程序中将 Foo.encode(with:)
中的 cx
转换为可以编码的内容(例如 [String : Int]
,反之亦然)。
请参阅