NSUserDefaults 自定义对象 - 属性列表对格式无效:200(属性列表不能包含“CFType”类型的对象)
Posted
技术标签:
【中文标题】NSUserDefaults 自定义对象 - 属性列表对格式无效:200(属性列表不能包含“CFType”类型的对象)【英文标题】:NSUserDefaults Custom object - Property list invalid for format: 200 (property lists cannot contain objects of type 'CFType') 【发布时间】:2014-10-03 07:34:57 【问题描述】:我一定是错误地使用了 NSUserDefaults 的自定义对象。错误“属性列表对格式无效:200(属性列表不能包含 'CFType' 类型的对象)”。下面是我的代码,Goal 类特别有趣,因为这是我采用 NSCoding 协议的地方。
此代码是全局的。
func saveGoals (goals : [Goal])
var updatedGoals = NSKeyedArchiver.archivedDataWithRootObject(goals)
NSUserDefaults.standardUserDefaults().setObject(updatedGoals, forKey: "Goals")
NSUserDefaults.standardUserDefaults().synchronize()
func loadCustomObjectWithKey() -> [Goal]
if let encodedObject : NSData = NSUserDefaults.standardUserDefaults().objectForKey("Goals") as? NSData
var encodedObject : NSData? = NSUserDefaults.standardUserDefaults().objectForKey("Goals") as? NSData
var goal : [Goal] = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObject!) as [Goal]
return goal
else
return [Goal]()
这段代码在GoalsViewController中。
class GoalsViewController: MainPageContentViewController, UITableViewDelegate, UITableViewDataSource
@IBOutlet var tableView: GoalsTableView!
var cell = GoalTableViewCell()
var goalsArray : Array<Goal> = [] //
override func viewDidLoad()
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
if var storedGoals: [Goal] = loadCustomObjectWithKey() as [Goal]?
goalsArray = storedGoals
//retrieve data.
var goal = Goal(title: "Walk the Dog")
goalsArray.append(goal)
saveGoals(goalsArray)
self.tableView?.reloadData()
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
var notification = NSNotificationCenter.defaultCenter()
notification.addObserver(self, selector: "finishCreatingGoal:", name: "FinishCreatingGoal", object: nil)
func finishCreatingGoal(notification : NSNotification)
if (notification.name == "FinishCreatingGoal")
var userInfo = notification.userInfo!
var text = userInfo["text"]! as String
var index = userInfo["index"]! as Int
var cell = self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0)) as GoalTableViewCell
goalsArray[index].title = cell.goalTextField.text
saveGoalList(goalsArray)
self.tableView.reloadData()
self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0), atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
此代码在目标类中。
import UIKit
class Goal : NSObject, NSCoding
var title : String? = ""
var checkmarked : Bool? = false
var isLastCell : Bool? = false
var enabled : Bool? = true
var priority = Priority.defaultPriority
override init()
init(title : String)
self.title = title
func encodeWithCoder(aCoder: NSCoder)
aCoder.encodeObject(title!, forKey: "title")
aCoder.encodeBool(checkmarked!, forKey: "checkmarked")
aCoder.encodeBool(isLastCell!, forKey: "isLastCell")
aCoder.encodeBool(enabled!, forKey: "enabled")
required init(coder aDecoder: NSCoder)
title = aDecoder.decodeObjectForKey("title") as String!
checkmarked = aDecoder.decodeBoolForKey("checkmarked") as Bool
isLastCell = aDecoder.decodeBoolForKey("isLastCell") as Bool
enabled = aDecoder.decodeBoolForKey("enabled") as Bool
【问题讨论】:
我猜你的目标对象的title
之一是零。这行:goalsArray[index].title = cell.goalTextField.text
是否保证将其设置为非零值?
是的,保证非零
【参考方案1】:
我将只从我拥有的工作项目中复制代码:
这是一个包含数学闪存卡游戏数据的 Game 对象类:
import Foundation
class GameData: NSObject
var sign: String = "+"
var level: Int = 1
var problems: Int = 10
var time: Int = 30
var skipWrong: Bool = true
var usedTime: Int = 0
var correctCount: Int = 0
var correctTopNumber: [Int] = [Int]()
var correctBottomNumber: [Int] = [Int]()
var wrongTopNumber: [Int] = [Int]()
var wrongBottomNumber: [Int] = [Int]()
var date: NSDate = NSDate()
func encodeWithCoder(aCoder: NSCoder!)
aCoder.encodeObject(sign, forKey: "sign")
aCoder.encodeInteger(level, forKey: "level")
aCoder.encodeInteger(problems, forKey: "problems")
aCoder.encodeInteger(time, forKey: "time")
aCoder.encodeBool(skipWrong, forKey: "skipWrong")
aCoder.encodeInteger(usedTime, forKey: "usedTime")
aCoder.encodeInteger(correctCount, forKey: "correctCount")
aCoder.encodeObject(correctTopNumber, forKey: "correctTopNumber")
aCoder.encodeObject(correctBottomNumber, forKey: "correctBottomNumber")
aCoder.encodeObject(wrongTopNumber, forKey: "wrongTopNumber")
aCoder.encodeObject(wrongBottomNumber, forKey: "wrongBottomNumber")
aCoder.encodeObject(date, forKey: "date")
init(coder aDecoder: NSCoder!)
sign = aDecoder.decodeObjectForKey("sign") as String
level = aDecoder.decodeIntegerForKey("level")
problems = aDecoder.decodeIntegerForKey("problems")
time = aDecoder.decodeIntegerForKey("time")
skipWrong = aDecoder.decodeBoolForKey("skipWrong")
usedTime = aDecoder.decodeIntegerForKey("usedTime")
correctCount = aDecoder.decodeIntegerForKey("correctCount")
correctTopNumber = aDecoder.decodeObjectForKey("correctTopNumber") as Array
correctBottomNumber = aDecoder.decodeObjectForKey("correctBottomNumber") as Array
wrongTopNumber = aDecoder.decodeObjectForKey("wrongTopNumber") as Array
wrongBottomNumber = aDecoder.decodeObjectForKey("wrongBottomNumber") as Array
date = aDecoder.decodeObjectForKey("date") as NSDate
override init()
这部分看起来和你的差不多,但变量类型更多。归档器和检索器类与您不同:
import Foundation
class ArchiveGameData:NSObject
var documentDirectories:NSArray = []
var documentDirectory:String = ""
var path:String = ""
func ArchiveResults(#dataSet: [GameData])
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("results3.archive")
if NSKeyedArchiver.archiveRootObject(dataSet, toFile: path)
//println("Success writing to file!")
else
println("Unable to write to file!")
func RetrieveGameData() -> NSObject
var dataToRetrieve = [GameData]()
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("results3.archive")
if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? [GameData]
dataToRetrieve = dataToRetrieve2
return(dataToRetrieve)
最后,用于在 ViewController 中存储和检索的代码:
//retrieveing
var gameDataArray = ArchiveGameData().RetrieveGameData() as [GameData]
//Archiving
gameData = GameData() //create local object then append all the new data, then store it
gameData.sign = buttonStates.sign
gameData.level = buttonStates.level
gameData.problems = buttonStates.problems
gameData.time = buttonStates.time
//etc. for all properties
ArchiveGameData().ArchiveResults(dataSet: gameDataArray)
【讨论】:
Steve,我认为将 NSCoding 协议添加到您的类声明 GameData 中是个好主意以上是关于NSUserDefaults 自定义对象 - 属性列表对格式无效:200(属性列表不能包含“CFType”类型的对象)的主要内容,如果未能解决你的问题,请参考以下文章
为啥 `NSUserDefaults` 不允许存储自定义类的对象?
将自定义对象存储到 NSMutableArray,然后将此 NSMutableArray 存储到 NSUserDefaults
如何在 Swift 中归档和取消归档自定义对象?或者如何在 Swift 中将自定义对象保存到 NSUserDefaults?