Swift-使用NSKeyedArchiver保存用户数据,转换为NSArray时出错

3

我有一个自定义对象的数组。当我尝试将该数组保存到NSUserDefaults时,我必须对它们进行归档。以下是我用于归档自定义对象数组的方法:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    //3

    var allMessages = defaults.objectForKey(UserDefaultsMesssageKey) as! [AddMessageViewController.harassText]
    var aMessage = AddMessageViewController.harassText(phoneNumber: 0, message: "1", frequency: 1, active: 1)
    allMessages.append(aMessage)
    saveMessage(allMessages)


    return (allMessages.count)
}

func archiveMessage(message:[AddMessageViewController.harassText]) -> NSData {
    let archivedObject = NSKeyedArchiver.archivedDataWithRootObject(message as NSArray)
    return archivedObject
}
func saveMessage(messages: [AddMessageViewController.harassText]) {
    let archivedObject = archiveMessage(messages)
    defaults.setObject(archivedObject, forKey: UserDefaultsMesssageKey)
    defaults.synchronize()
}
func retrieveData()-> [AddMessageViewController.harassText]? {
    if let unarchiveObject = NSUserDefaults.standardUserDefaults().objectForKey(UserDefaultsMesssageKey) as? NSData {
        return NSKeyedUnarchiver.unarchiveObjectWithData(unarchiveObject) as? [AddMessageViewController.harassText]
    }
    return nil
}

流程如下:
  1. On saveMessage call, pass the custom array in to get archived. Here is what the array looks like to GDB. You can see that it is an array, and it has 1 class object contained in it.

    ([Harass_Your_Kate.AddMessageViewController.harassText]) $R0 = 1 value { [0] = 0x00007fa5ab409600 { ObjectiveC.NSObject = { isa = Harass_Your_Kate.AddMessageViewController.harassText } phoneNumber = 0 message = "1" frequency = 1 active = 1 } }

  2. The array gets passed into archiveMessage. The code immediately fails on the NSKeyedArchiver method. The Error message is as follows :

    [_TtCC16Harass_Your_Kate24AddMessageViewController10harassText encodeWithCoder:]: unrecognized selector sent to instance 0x7fa5ab409600
    

    2016-07-15 16:31:26.019 Harass Your Kate[5858:7847495] * -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it. 2016-07-15 16:31:26.023 Harass Your Kate[5858:7847495] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_TtCC16Harass_Your_Kate24AddMessageViewController10harassText encodeWithCoder:]: unrecognized selector sent to instance 0x7fa5ab409600

我很感激所有的帮助,提前谢谢!
编辑:这是我的对象定义:
class Text : NSObject {
    var phoneNumber = 0             //Text address to send to
    var message: String = ""        //Message to be sent
    var frequency = 24              //Number of hours between messages (usually a multiple of 24 - 24 = daily)
    var active = 0                  // 0 if cancelled, 1 if active

    init(phoneNumber: Int, message: String, frequency: Int, active: Int ){
        self.phoneNumber = phoneNumber
        self.message = message
        self.frequency = frequency
        self.active = active
    }
}

2
我们需要查看您自定义对象的NSCoding方法(initWithCoderencodeWithCoder)。 - Duncan C
我两样都没有。 - Code Wiget
1
那就是问题所在了。请展示您自定义类的定义。 (编辑您的问题以添加代码,不要在评论中发布它。) - Duncan C
1
除非每个对象都符合NSCoding(这意味着它必须实现initWithCoder和encodeWithCoder),否则您无法使用“NSCoding”将“对象图”转换为NSData。如果您尝试对包含对象的容器(如数组或字典)进行编码,则容器中的所有对象都必须符合NSCoding,否则它将无法正常工作。 - Duncan C
@DuncanC,非常感谢您的帮助。在我的编辑中,我包含了自定义类的定义。关于NSCoding,我感到非常困惑,因为我以前从未使用过这个,而且当然没有在保存自定义类数组的上下文中使用过。但再次感谢您抽出时间来帮助我。期待再次收到您的回信。 - Code Wiget
1个回答

3

NSKeyedArchiver利用实现了NSCoding协议的方法序列化对象。它无法自动推断如何保存您的自定义类;您需要按照以下方式自己实现:

class Text : NSObject, NSCoding {
    var phoneNumber = 0             //Text address to send to
    var message: String = ""        //Message to be sent
    var frequency = 24              //Number of hours between messages (usually a multiple of 24 - 24 = daily)
    var active = 0                  // 0 if cancelled, 1 if active

    init(phoneNumber: Int, message: String, frequency: Int, active: Int ){
        self.phoneNumber = phoneNumber
        self.message = message
        self.frequency = frequency
        self.active = active
    }

    required init?(coder aDecoder: NSCoder) {
        phoneNumber = aDecoder.decodeInteger(forKey: "phoneNumber")
        message = aDecoder.decodeObject(forKey: "message") as! String
        frequency = aDecoder.decodeInteger(forKey: "frequency")
        active = aDecoder.decodeInteger(forKey: "active")
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(phoneNumber, forKey: "phoneNumber")
        aCoder.encode(message, forKey: "message")
        aCoder.encode(frequency, forKey: "frequency")
        aCoder.encode(active, forKey: "active")
    }
}

正如您所看到的,初始化程序从编码器中读取并创建实例,而encode方法将相关信息保存到编码器中。在像这样简单的类中,它们的实现可能似乎很显然,但在更复杂的自定义类型中,需要做出非平凡的编码决策。

谢谢!这个很好用。我也在使用CoreData实现它,这似乎更简单地存储自定义信息。 - Code Wiget

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接