Swift中的NSCoding - 解码类对象数组会引发错误

时间:2015-12-24 15:50:27

标签: ios swift

这是我的 Game 对象的代码。它有很多不同的属性,其中一个是 Cards 的数组。当我尝试使用NSCoding保存我的游戏对象时,XCode会抛出此错误

  

***由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [Hearthstone_Tracker.Card encodeWithCoder:]:无法识别的选择器发送到实例0x7fbca9db9750'

从我读过的内容来看,这些错误经常发生在UIButton调用函数时,并在函数不期望它时将自身作为参数传递,反之亦然。我不知道它如何适用于我的情况。

我读过NSCoding有一些结构问题,但由于卡实际上是一个类,我不认为问题就在那里。

这是我的游戏类:

import Foundation
import UIKit

class Game: NSObject, NSCoding {

// MARK: Properties

let playerHero: String
let playerDeck: String
let playerImage: UIImage?

let opponentHero: String
let opponentDeck: String
let opponentImage: UIImage?

let result: String
let coin: Bool
var date: String?
let mode: String
let rank: String?
let duration: Int?
let durationSec: Int?
let id: Int

let cardsPlayed: [Card]

var manaEfficiency: (Double, Double)?
var turnCount: Int?
var estimatedTurnLength: Int?
var finisher: String?

// MARK: Keys for the data

struct PropertyKey {
    static let playerHero = "playerHero"
    static let playerDeck = "playerDeck"
    static let playerImage = "playerImage"

    static let opponentHero = "opponentHero"
    static let opponentDeck = "opponentDeck"
    static let opponentImage = "opponntImage"

    static let result = "result"
    static let coin = "coin"
    static let date = "date"
    static let mode = "mode"
    static let rank = "rank"
    static let duration = "duration"
    static let durationSec = "durationSec"
    static let id = "id"

    static let cardsPlayed = "cardsPlayed"
}

// MARK: Archiving Paths

static let DocumentsDirectory: AnyObject = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("games")

// MARK: Initializer

init(playerHero: String, playerDeck: String, opponentHero: String, opponentDeck: String, result: String, coin: Bool, date: String, mode: String, rank: String, duration: Int?, durationSec: Int?, id: Int, cardsPlayed: [Card]) {
    // ...
    // Some initializer code
    // ...  

    self.cardsPlayed = cardsPlayed

    super.init()
}

// MARK: NSCoding

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(playerHero, forKey: PropertyKey.playerHero)
    aCoder.encodeObject(playerDeck, forKey: PropertyKey.playerDeck)

    aCoder.encodeObject(opponentHero, forKey: PropertyKey.opponentHero)
    aCoder.encodeObject(opponentDeck, forKey: PropertyKey.opponentDeck)

    aCoder.encodeObject(result, forKey: PropertyKey.result)
    aCoder.encodeBool(coin, forKey: PropertyKey.coin)
    aCoder.encodeObject(date, forKey: PropertyKey.date)
    aCoder.encodeObject(mode, forKey: PropertyKey.mode)
    aCoder.encodeObject(rank, forKey: PropertyKey.rank)
    aCoder.encodeObject(duration, forKey: PropertyKey.duration)
    aCoder.encodeObject(durationSec, forKey: PropertyKey.durationSec)
    aCoder.encodeObject(id, forKey: PropertyKey.id)

    aCoder.encodeObject(cardsPlayed, forKey: PropertyKey.cardsPlayed)
}

required convenience init?(coder aDecoder: NSCoder) {
    let playerHero = aDecoder.decodeObjectForKey(PropertyKey.playerHero) as! String
    let playerDeck = aDecoder.decodeObjectForKey(PropertyKey.playerDeck) as! String

    let opponentHero = aDecoder.decodeObjectForKey(PropertyKey.opponentHero) as! String
    let opponentDeck = aDecoder.decodeObjectForKey(PropertyKey.opponentDeck) as! String

    let result = aDecoder.decodeObjectForKey(PropertyKey.result) as! String
    let coin = aDecoder.decodeBoolForKey(PropertyKey.coin)
    let date = aDecoder.decodeObjectForKey(PropertyKey.date) as! String
    let mode = aDecoder.decodeObjectForKey(PropertyKey.mode) as! String
    let rank = aDecoder.decodeObjectForKey(PropertyKey.rank) as! String
    let duration = aDecoder.decodeObjectForKey(PropertyKey.duration) as? Int
    let durationSec = aDecoder.decodeObjectForKey(PropertyKey.durationSec) as? Int
    let id = aDecoder.decodeObjectForKey(PropertyKey.id) as! Int

    let cardsPlayed = aDecoder.decodeObjectForKey(PropertyKey.cardsPlayed) as! [Card]

    self.init(playerHero: playerHero, playerDeck: playerDeck, opponentHero: opponentHero, opponentDeck: opponentDeck, result: result, coin: coin, date: date, mode: mode, rank: rank, duration: duration, durationSec: durationSec, id: id, cardsPlayed: cardsPlayed)
}

这是类:

import Foundation
import UIKit

class Card: NSObject {

// MARK: Properties

let name: String
let manacost: Int
let turn: Int
let player: String

// MARK: Initialzer

init(name: String, manacost: Int, turn: Int, player: String) {
    self.name = name
    self.manacost = manacost
    self.turn = turn
    self.player = player

    super.init()
}

}

1 个答案:

答案 0 :(得分:2)

每个对象及其内部子对象 的层次结构)能够存储在NSDefaults中必须能够序列化本身......那是......必须符合NSCoding