Arrays 在Swift中使用NSCoding存档可选结构的数组?
我在Obj-C中做了很多NSCoding归档工作,但我不确定它如何处理Swift中的结构,也不确定它如何处理具有可选值的数组。这是我的密码:Arrays 在Swift中使用NSCoding存档可选结构的数组?,arrays,struct,swift,nscoding,optional,Arrays,Struct,Swift,Nscoding,Optional,我在Obj-C中做了很多NSCoding归档工作,但我不确定它如何处理Swift中的结构,也不确定它如何处理具有可选值的数组。这是我的密码: public struct SquareCoords { var x: Int, y: Int } 这是我需要存储的类: public class Player: NSCoding { var playerNum: Int var name = "" private var moveHistory: [SquareCoor
public struct SquareCoords {
var x: Int, y: Int
}
这是我需要存储的类:
public class Player: NSCoding {
var playerNum: Int
var name = ""
private var moveHistory: [SquareCoords?] = []
init (playerNum: Int, name: String) {
self.playerNum = playerNum
self.name = name
}
public required init(coder aDecoder: NSCoder!) {
playerNum = aDecoder.decodeIntegerForKey("playerNumKey")
name = aDecoder.decodeObjectForKey("nameKey") as String
moveHistory = aDecoder.decodeObjectForKey("moveHistoryKey") as [SquareCoords?]
}
public func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(playerNum, forKey: "playerNumKey")
aCoder.encodeObject(name, forKey: "nameKey")
aCoder.encodeObject(moveHistory, forKey: "moveHistoryKey")
}
...
在编码器初始化的最后一行,我在XCode中得到了以下错误消息:
'AnyObject' is not convertible to [SquareCoords?]'
在encodeWithEncoder的最后一行:
Extra argument 'forKey' in call
有人能让我朝着正确的方向前进吗?我不确定确切的问题是什么,但如果您使用NSMutableArray而不是Swift数组,问题就会解决:
public struct SquareCoords {
var x: Int, y: Int
}
public class Player: NSCoding {
var playerNum: Int
var name = ""
var moveHistory: NSMutableArray = NSMutableArray()
init (playerNum: Int, name: String) {
self.playerNum = playerNum
self.name = name
}
public required init(coder aDecoder: NSCoder!) {
playerNum = aDecoder.decodeIntegerForKey("playerNumKey")
name = aDecoder.decodeObjectForKey("nameKey") as String
moveHistory = aDecoder.decodeObjectForKey("moveHistoryKey") as NSMutableArray
}
public func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(playerNum, forKey: "playerNumKey")
aCoder.encodeObject(name, forKey: "nameKey")
aCoder.encodeObject(moveHistory, forKey: "moveHistoryKey")
}
}
似乎在这种情况下,当aDecoder.decodeObjectForKey返回隐式展开的AnyObject时,它不会强制转换为SquareCoords数组
我进一步研究了这个问题,发现它可能与struct的使用有关。(您正在创建一个值类型的结构数组。)这有点猜测,但我注意到,如果类类型用于SquareCoords,则没有问题,例如
public class SquareCoords {
var x: Int = 0, y: Int = 0
}
public class Player: NSCoding {
var playerNum: Int
var name = ""
private var moveHistory: [SquareCoords] = [SquareCoords]()
init (playerNum: Int, name: String) {
self.playerNum = playerNum
self.name = name
}
public required init(coder aDecoder: NSCoder!) {
playerNum = aDecoder.decodeIntegerForKey("playerNumKey")
name = aDecoder.decodeObjectForKey("nameKey") as String
moveHistory = aDecoder.decodeObjectForKey("moveHistoryKey") as [SquareCoords]
}
public func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(playerNum, forKey: "playerNumKey")
aCoder.encodeObject(name, forKey: "nameKey")
aCoder.encodeObject(moveHistory, forKey: "moveHistoryKey")
}
}
可能由于某种原因,任何对象的强制转换都无法转换为结构数组。-我相信其他人可以提供更多的见解,希望这能有所帮助!斯威夫特可以是狂暴的:D在苹果州:
Swift为处理非特定类型提供了两个特殊类型别名:-
AnyObject
可以表示任何类类型的实例。-
Any
可以表示任何类型的实例,包括函数类型
知道了这一点,类型SquareCoords
(Swift结构)和类型[SquareCoords]
(Swift结构的Swift数组)不能符合协议任何对象
另一方面,decodeObjectForKey:
需要一个符合协议AnyObject
的参数,encodeObject:forKey:
返回AnyObject
。因此,以下两行无法编译:
moveHistory = aDecoder.decodeObjectForKey("moveHistoryKey") as [SquareCoords?]
aCoder.encodeObject(moveHistory, forKey: "moveHistoryKey")
因此,除非您找到一种方法使SquareCoords
符合协议AnyObject
(我不知道这是否可行),否则您必须将SquareCoords
从Swift结构转换为类
PS:
在这一点上,您可能会问:“好吧,但是,类型<代码>字符串——实际上是一个快捷的结构——怎么可能符合协议<代码>任何对象< /代码>?“嗯,那是因为<代码>字符串< /代码>被无缝地连接到基金会的代码> NString < /Cord>类。(
Array
,Dictionary
以相同的方式桥接到NSArray
和NSDictionary
)。如果你想更好地了解它,请阅读。除了NSCoding不支持上面提到的结构之外,我的建议是,你的类也应该继承NSObject,以便能够对自身及其属性进行编码和解码。这里给出的其他答案解决了你的问题。但是,我最近在le试图归档我的Swift结构,并想出了一个有趣的方法来解决这个问题。NSCoding不支持结构
从本质上讲,以下方法涉及将结构属性转换为字典元素。但是,它可以优雅地使用协议来实现这一点。您只需定义一个协议,该协议实现两种方法,这两种方法有助于对结构进行字典化和取消字典化。使用协议和泛型的优势在于当一个结构是另一个结构的属性时工作。这种嵌套可以达到任何深度
我将该协议称为“Dictionarable”,这表示任何符合该协议的内容都可以转换为字典
protocol Dictionariable {
func dictionaryRepresentation() -> NSDictionary
init?(dictionaryRepresentation: NSDictionary?)
}
现在,考虑一个结构“电影”
struct Movie {
let name: String
let director: String
let releaseYear: Int
}
让我扩展这个结构,使它符合“字典化”协议
extension Movie: Dictionariable {
func dictionaryRepresentation() -> NSDictionary {
let representation: [String: AnyObject] = [
"name": name,
"director": director,
"releaseYear": releaseYear
]
return representation
}
init?(dictionaryRepresentation: NSDictionary?) {
guard let values = dictionaryRepresentation else {return nil}
if let name = values["name"] as? String,
director = values["director"] as? String,
releaseYear = values["releaseYear"] as? Int {
self.name = name
self.director = director
self.releaseYear = releaseYear
} else {
return nil
}
}
}
基本上,我们现在有一种方法可以安全地将一个结构转换为一个字典。我说安全是因为我们实现了字典是如何形成的,每个结构都是独立的。只要这个实现是正确的,功能就可以工作。从字典中恢复结构的方法是使用一个失败的初始化器。它必须是fai标签,因为文件损坏和其他原因可能会使存档中的结构实例化不完整。这可能永远不会发生,但更安全的是,它是可失败的
func extractStructuresFromArchive<T: Dictionariable>() -> [T] {
guard let encodedArray = NSKeyedUnarchiver.unarchiveObjectWithFile(path()) as? [AnyObject] else {return []}
return encodedArray.map{$0 as? NSDictionary}.flatMap{T(dictionaryRepresentation: $0)}
}
func archiveStructureInstances<T: Dictionariable>(structures: [T]) {
let encodedValues = structures.map{$0.dictionaryRepresentation()}
NSKeyedArchiver.archiveRootObject(encodedValues, toFile: path())
}
//Method to get path to encode stuctures to
func path() -> String {
let documentsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).first
let path = documentsPath?.stringByAppendingString("/Movie")
return path!
}
func extracturesformarchive()->[T]{
guard let encodedArray=NSKeyedUnarchiver.unarchiveObjectWithFile(path())为?[AnyObject]else{return[]}
返回encodedArray.map{$0 as?NSDictionary}.flatMap{T(dictionaryRepresentation:$0)}
}
func archiveStructureInstances(结构:[T]){
让encodedValues=structures.map{$0.dictionaryRepresentation()}
归档对象(encodedValue,toFile:path())
}
//方法来获取将结构编码到的路径
func path()->字符串{
让documentsPath=NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.UserDomainMask,true)
让path=documentsPath?.stringByAppendingString(“/Movie”)
返回路径!
}
上述两种方法可以存档和取消存档一系列“电影”结构。您需要注意的是对每个需要存档的结构实施“可词典化”协议
检查我写的比较存档和非存档swift结构的三种方法的代码。上面解释的代码有一个更详细的实现和一个游乐场文件,您可以在链接中运行和测试。强制转换失败的原因是任何对象只能是类的实例,而不是结构/枚举/元组。@Lance谢谢!-如果我理解正确解码ObjectForkey返回一个AnyObject,而我们不能将其转换为一个Swift结构数组?--你认为处理这个问题的最佳方法是什么?--使用NSMutableArray?还是使用类而不是结构?@John谢谢……这让我找到了正确的解决方法!我现在已经确定非移动(玩家运行)