ios - NSKeyedUnarchiver 不会返回数据

标签 ios swift nskeyedarchiver nskeyedunarchiver

我正在制作一个跟踪用户锻炼情况的应用程序。我有两个自定义类,第一个是 ExerciseModel,它保存锻炼期间执行的每个练习的数据,包括名称、组数、次数等。这是我的数据模型:

import UIKit

class ExerciseModel: NSObject, NSCoding
{
// MARK: Properties
var name: String
var sets: Int
var reps: Int
var heartrate: Int?
var type: String?

//MARK: Archiving Paths
static let DocumentsDirectory = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("exercises")


// MARK: Initialization
init?(name: String, sets: Int, reps: Int, heartrate: Int?, type: String)
{

// MARK: Initlaize stored properties
self.name = name
self.sets = sets
self.reps = reps
self.heartrate = heartrate
self.type = type

super.init()


// Initialization should fail if there is no name or sets is negative
if name.isEmpty || sets < 0
    {
        return nil
    }

}

struct PropertyKey
{
    static let nameKey = "name"
    static let setKey = "sets"
    static let repKey = "reps"
    static let heartrateKey = "heartrate"
    static let typekey = "type"
}


// MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder)
{
    aCoder.encodeObject(name, forKey: PropertyKey.nameKey)
    aCoder.encodeInteger(sets, forKey: PropertyKey.setKey)
    aCoder.encodeInteger(reps, forKey: PropertyKey.repKey)
    aCoder.encodeObject(type, forKey: PropertyKey.typekey)
}

required convenience init?(coder aDecoder: NSCoder)
{
    let name = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
    let sets = aDecoder.decodeIntegerForKey(PropertyKey.setKey)
    let reps = aDecoder.decodeIntegerForKey(PropertyKey.repKey)
    let heartrate = aDecoder.decodeIntegerForKey(PropertyKey.heartrateKey)
    let type = aDecoder.decodeObjectForKey(PropertyKey.typekey) as? String

    // Must call designated initializer
    self.init(name: name, sets: sets, reps: reps, heartrate: heartrate, type: type!)
}

init?(name: String, sets: Int, reps: Int, heartrate: Int, type: String)
{
    // Initialize stored properties.
    self.name = name
    self.sets = sets
    self.reps = reps
    self.heartrate = heartrate
    self.type = type

}


}

我的第二个自定义类称为WorkoutStorage,这意味着用户可以保存整个锻炼并在以后检索它们。如上所述,锻炼属性是锻炼模型对象的数组。这是我的 WorkoutStorage 数据模型:

//

import UIKit

@objc(WorkoutStorage)
class WorkoutStorage: NSObject, NSCoding
{
// MARK: Properties
var name: String
var date: NSDate
var exercises: [ExerciseModel]
var maxHR: Int
var avgHR: Int

// MARK: Archiving Paths
static let DocumentsDirectory = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("storedWorkouts")

// MARK: Initialization
init?(name: String, date: NSDate, exercises: [ExerciseModel], maxHR: Int, avgHR: Int)
{
    //MARK: Initialize Stored Properties
    self.name = name
    self.date = date
    self.exercises = exercises
    self.maxHR = maxHR
    self.avgHR = avgHR

    super.init()

}

struct PropertyKey
{
    static let nameKey = "name"
    static let dateKey = "date"
    static let exercisesKey = "exercises"
    static let maxHRKey = "maxHR"
    static let avgHRKey = "avgHR"
}

// MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder)
{
    aCoder.encodeObject(name, forKey: PropertyKey.nameKey)
    aCoder.encodeObject(date, forKey: PropertyKey.dateKey)
    aCoder.encodeObject(exercises, forKey: PropertyKey.exercisesKey)
    aCoder.encodeInteger(maxHR, forKey: PropertyKey.maxHRKey)
    aCoder.encodeInteger(avgHR, forKey: PropertyKey.avgHRKey)
}

required convenience init?(coder aDecoder: NSCoder)
{
    let name = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
    let date = aDecoder.decodeObjectForKey(PropertyKey.dateKey) as! NSDate
    let exercises = aDecoder.decodeObjectForKey(PropertyKey.exercisesKey) as! [ExerciseModel]
    let maxHR = aDecoder.decodeIntegerForKey(PropertyKey.maxHRKey)
    let avgHR = aDecoder.decodeIntegerForKey(PropertyKey.avgHRKey)

    // Must call designated initializer
    self.init(name: name, date: date, exercises: exercises, maxHR: maxHR, avgHR: avgHR)
}
}

我按照 Apple 持久数据教程为此设置了 NSKeyedArchiver 和 NSKeyedUnarchiver,但我在检索数据时仍然遇到问题。当我尝试加载锻炼时,我调用以下函数:

func loadStoredWorkouts() -> WorkoutStorage
{
    NSKeyedUnarchiver.setClass(WorkoutStorage.self, forClassName: "WorkoutStorage")
    NSKeyedArchiver.setClassName("WorkoutStorage", forClass: WorkoutStorage.self)

    print("\(WorkoutStorage.ArchiveURL.path!)")

    return NSKeyedUnarchiver.unarchiveObjectWithFile(WorkoutStorage.ArchiveURL.path!) as! WorkoutStorage
}

目前我只能返回一个 WorkoutStorage 对象,但是当我尝试检索包含所有存储的 WorkoutStorage 对象的数组时,我收到一条错误消息: 无法转换“Workout_Tracker.WorkoutStorage”类型的值 (0x1000fcc80 )到“NSArray”(0x19f6b2418)。我已经阅读了很多文档,试图找出为什么这只会返回一个对象,并检查了具有类似问题的问题,但无济于事。我最初按照 Apple Persist Data 教程设置我的应用程序来存储和加载我的 ExerciseModel 对象,这似乎工作完美。我以相同的方式设置了 WorkoutStorage 类,但这里似乎存在问题。

任何帮助将不胜感激!!

**编辑* 以下是我用来存档 WorkoutStorage 对象的代码:

func saveWorkoutStorageObject(currentWorkout: WorkoutStorage)
    {
        NSKeyedUnarchiver.setClass(WorkoutStorage.self, forClassName: "WorkoutStorage")
        NSKeyedArchiver.setClassName("WorkoutStorage", forClass: WorkoutStorage.self)

    let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(currentWorkout, toFile: WorkoutStorage.ArchiveURL.path!)
    if !isSuccessfulSave
    {
        print("Failed to save exercises")
    }
    if isSuccessfulSave
    {
        print("Successful save of current workout: \(currentWorkout)")
    }
}

用户一次只能创建一项锻炼,因此每次完成一项锻炼后,我都会将该对象传递给上述函数以将其存档。

为了取消归档所有对象,我尝试执行以下操作:

var workouts = [WorkoutStorage]()

override func viewDidLoad()
{
    super.viewDidLoad()

    workouts = loadStoredWorkouts()
}

其中 loadStoredWorkouts() 函数将是:

 func loadStoredWorkouts() -> [WorkoutStorage]
    {
        NSKeyedUnarchiver.setClass(WorkoutStorage.self, forClassName: "WorkoutStorage")
        NSKeyedArchiver.setClassName("WorkoutStorage", forClass: WorkoutStorage.self)

    print("\(WorkoutStorage.ArchiveURL.path!)")

    return NSKeyedUnarchiver.unarchiveObjectWithFile(WorkoutStorage.ArchiveURL.path!) as! [WorkoutStorage]
}

最佳答案

您的saveWorkoutStorageObject仅存档一次锻炼。它不会存档数组,因此您当然无法取消存档数组。

如果您希望能够取消存档数组,则需要存档 workouts 数组。

每次将某些内容存档到文件中时,都会替换该文件的内容。它不会附加到末尾。

由于 NSKeyedArchiver.archiveRootObject 自动存档子对象,您所需要做的就是存档数组,您的 WorkoutStorage 对象将自动存档

func saveWorkouts(workouts:[WorkoutStorage])
{
    let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(workouts, toFile: WorkoutStorage.ArchiveURL.path!)
    if isSuccessfulSave
    {
        print("Successful save of workouts: \(workouts)")
    } else {
        print("Failed to save exercises")
    }
}

关于ios - NSKeyedUnarchiver 不会返回数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37737351/

相关文章:

ios - NSKeyedArchiver 不会保存或加载对象

ios - 初学者 : Need Help Accessing Magnetometer Data using Swift

swift - 是否可以在 Swift 中编写代码并部署到 Windows 上的真实设备?

ios - 如何在 Swift 中使用 NSURLSessionDataTask

快速 fatal error : unexpectedly found nil while unwrapping an Optional value in adMob

ios - Mac 和 iOS 之间的 NSData 结构

ios - NSKeyedUnarchiver unarchiveObjectWithData : not working

ios - 从变量中获取 NSURL 中的字符串

ios - 具有负 M_PI 的 CGAffineTransformMakeRotation

ios - AVCaptureSession 和背景音频 iOS 7