如果你想让泛型类采用NSCoding
和泛型类型T
然后将被编码和解码T
必须是符合属性列表的类型之一.
符合属性列表的类型有NSString
, NSNumber
, NSDate
and NSData
一个可能的解决方案是创建一个协议PropertyListable
并将属性列表兼容类型的所有 Swift 等效项扩展到该协议
协议要求是
- An
associated type
.
- 计算属性
propertyListRepresentation
将值转换为符合属性列表的类型。
- 初始化器
init(propertyList
做相反的事情。
public protocol PropertyListable {
associatedtype PropertyListType
var propertyListRepresentation : PropertyListType { get }
init(propertyList : PropertyListType)
}
以下是示例性实现String
and Int
.
extension String : PropertyListable {
public typealias PropertyListType = String
public var propertyListRepresentation : PropertyListType { return self }
public init(propertyList: PropertyListType) { self.init(stringLiteral: propertyList) }
}
extension Int : PropertyListable {
public typealias PropertyListType = Int
public var propertyListRepresentation : PropertyListType { return self }
public init(propertyList: PropertyListType) { self.init(propertyList) }
}
让我们声明一个示例枚举并采用PropertyListable
enum Foo : Int, PropertyListable {
public typealias PropertyListType = Int
case north, east, south, west
public var propertyListRepresentation : PropertyListType { return self.rawValue }
public init(propertyList: PropertyListType) {
self.init(rawValue: propertyList)!
}
}
最后将您的泛型类替换为
open class SMState<T: PropertyListable>: NSObject, NSCoding {
open var value: T
open var didEnter: ( (_ state: SMState<T>) -> Void)?
open var didExit: ( (_ state: SMState<T>) -> Void)?
public init(_ value: T) {
self.value = value
}
convenience required public init(coder decoder: NSCoder) {
let value = decoder.decodeObject(forKey: "value") as! T.PropertyListType
self.init(T(propertyList: value))
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(value.propertyListRepresentation, forKey: "value")
}
}
通过此实现,您可以创建一个实例并将其存档
let currentState = SMState<Foo>(Foo.north)
let stateEncodeData = NSKeyedArchiver.archivedData(withRootObject: currentState)
并再次取消存档
let restoredState = NSKeyedUnarchiver.unarchiveObject(with: stateEncodeData) as! SMState<Foo>
print(restoredState.value)
整个解决方案似乎很麻烦,但你必须满足以下限制:NSCoding
需要符合属性列表的类型。如果您不需要像这样的自定义类型enum
实施更加容易(而且更短)。