在Swift中保留一组自定义结构

时间:2016-01-02 23:58:10

标签: arrays swift struct nsuserdefaults persist

我正在尝试存储一组自定义结构。

在下面的尝试中,我在saveSampleArrayOfQuerySettings()的第二行中遇到运行时错误,抱怨转换为AnyObject。

struct QuerySettings {

    //    let ARRAY_INDEX_WHERE_TO_SAVE_STRUCT = 0

    let QUERY_SETTINGS_KEY = "querysettings"
    let defaults = NSUserDefaults.standardUserDefaults()

    private var _includeCompletedReminders: Bool = false        // Default value
    var includeCompletedReminders: Bool {
        get {
            // If value has been set before then use it otherwise retrieve it.
            return _includeCompletedReminders
        } set (newVal) {
            _includeCompletedReminders = newVal
            //            saveSettings(self, index: ARRAY_INDEX_WHERE_TO_SAVE_STRUCT, saveKey: QUERY_SETTINGS_KEY)
        }
    }

    private var _includeRemindersWithNoDueDate: Bool = true
    var includeRemindersWithNoDueDate: Bool {
        get {
            return _includeRemindersWithNoDueDate
        } set (newVal) {
            _includeRemindersWithNoDueDate = newVal
            //            saveSettings(self, index: ARRAY_INDEX_WHERE_TO_SAVE_STRUCT, saveKey: QUERY_SETTINGS_KEY)
        }
    }
}

func saveSampleArrayOfQuerySettings(saveKey: String) {
    let sampleArray = [QuerySettings(), QuerySettings()]

    // Persist
    let archivedSettingsArray = NSKeyedArchiver.archivedDataWithRootObject(sampleArray as! AnyObject)

    // RUNTIME ERROR AT PREVIOUS LINE: "Could not cast value of type 'Swift.Array<RemindersPro.QuerySettings>' (0x112df10d8) to 'Swift.AnyObject' (0x1169d6018)."

    NSUserDefaults.standardUserDefaults().setObject(archivedSettingsArray, forKey: saveKey)
    NSUserDefaults.standardUserDefaults().synchronize()

    // For Testing Purposes - Load the saved settings
    if let retrievedArchivedSettingsArray : AnyObject = NSUserDefaults.standardUserDefaults().objectForKey(saveKey) {
        if let settingsArray : AnyObject = NSKeyedUnarchiver.unarchiveObjectWithData(retrievedArchivedSettingsArray as! NSData) {
            let arr = settingsArray as! [QuerySettings]
            print(arr.first)
        }
    }
}

saveSampleArrayOfQuerySettings("saveKey")

我想知道是否需要对结构进行编码。我查看了这些帖子,但奇怪的是甚至无法让帖子中的样本正常工作(更不用说将它们应用到我的代码中了。)

How to save an array of objects to NSUserDefault with swift?

(Swift) Storing and retrieving Array to NSUserDefaults

How to save an array of custom structs to plist swift

请告诉我如何使其正常工作?

1 个答案:

答案 0 :(得分:4)

你的代码太冗长了:

  1. 您不需要明确定义类型。分配默认值truefalse足以让编译器推导出您想要的Bool。 Swift是围绕这样的想法而构建的,即编译器可以非常智能地减轻程序员的负担。
  2. 你的自定义getter和setter没什么特别的,所以最好让Swift自动合成它。
  3. 现在,关于归档的主题:您将会惊愕地了解NSCoding仅适用于从NSObject继承的对象。结构不能与NSCoding一致。你需要把它包装在一个帮助器类中。

    以下是我提出的建议:

    1。定义一个辅助类来序列化结构:

    protocol ArchivableStruct {
        var dataDictionary: [String: AnyObject] { get }
        init(dataDictionary aDict: [String: AnyObject])
    }
    
    class StructArchiver<T: ArchivableStruct>: NSObject, NSCoding {
        var structValue: T
    
        init(structValue: T) {
            self.structValue = structValue
        }
    
        func encodeWithCoder(aCoder: NSCoder) {
            aCoder.encodeObject(self.structValue.dataDictionary, forKey: "dataDictionary")
        }
    
        required init?(coder aDecoder: NSCoder) {
            let dataDictionary = aDecoder.decodeObjectForKey("dataDictionary") as! [String: AnyObject]
            self.structValue = T(dataDictionary: dataDictionary)
        }
    }
    

    2。将结构中的数据导出到Dictionary

    字典是归档的。在回来的路上,我们只需解压缩这个Dictionary来获取结构。我们无需担心QUERY_SETTINGS_KEYdefaults,因为前者是常量,后者有自己的数据源(NSUserDefaults)。

    struct QuerySettings: ArchivableStruct {
        let QUERY_SETTINGS_KEY = "querysettings"
        let defaults = NSUserDefaults.standardUserDefaults()
    
        var includeCompletedReminders = false
        var includeRemindersWithNoDueDate = true
    
        init(includeCompletedReminders: Bool, includeRemindersWithNoDueDate: Bool) {
            self.includeCompletedReminders = includeCompletedReminders
            self.includeRemindersWithNoDueDate = includeRemindersWithNoDueDate
        }
    
        // --------------------------------------
        // ArchivableStruct protocol
        // --------------------------------------
        var dataDictionary: [String: AnyObject] {
            get {
                return [
                    "includeCompletedReminders": self.includeCompletedReminders,
                    "includeRemindersWithNoDueDate": self.includeRemindersWithNoDueDate
                ]
            }
        }
    
        init(dataDictionary aDict: [String : AnyObject]) {
            self.includeCompletedReminders = aDict["includeCompletedReminders"] as! Bool
            self.includeRemindersWithNoDueDate = aDict["includeRemindersWithNoDueDate"] as! Bool
        }
    }
    

    3。从struct映射到帮助程序类

    由于您没有归档QuerySetting结构但是它们的数组,因此还有一个额外步骤可将其映射到StructArchiver<T>,以便您的数组可以存档:

    // Set up a sample array
    let a = QuerySettings(includeCompletedReminders: true, includeRemindersWithNoDueDate: false)
    let b = QuerySettings(includeCompletedReminders: false, includeRemindersWithNoDueDate: true)
    let sampleArray = [a, b]
    
    // Archive
    let wrapperArray = sampleArray.map { StructArchiver(structValue: $0) }
    let data = NSKeyedArchiver.archivedDataWithRootObject(wrapperArray)
    
    // Unarchive
    let unwrapperArray = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [StructArchiver<QuerySettings>]
    let unarchivedArray = unwrapperArray.map { $0.structValue }