尝试保存到NSUserdefaults时出错 [英] Error when trying to save to NSUserdefaults
问题描述
我有一个表,其工作方式如下.如果选择了一行,则将与所选行相对应的数量添加到var total
,并添加一个选中标记.如果取消选择,则将减去金额,复选标记将被设置为none.
在尝试将数据保存到NSUserDefaults或从NSUserDefaults检索数据之前,我的代码正常工作.
错误是:当我选择第一行时,它减去了金额而不是加了;选定一行后,如果我点击后退"按钮,然后返回到同一屏幕,则不会显示选中标记.
在此构造中,当我尝试从NSUserDefaults检索时,即使我在进行赋值之前检查了if indexPathForCellSelected != nil
,indexPathForCellSelected
的计算结果仍为nil.
致命错误:解开可选值时意外发现nil
I have a table which works in the following way. If a row is selected, an amount corresponding to the selected row is added to var total
, a checkmark is added. If it is deselected, the amount will be subtracted, the checkmark will be set to none.
My code worked properly before trying to save/retrieve the data to/from NSUserDefaults.
The errors are: when I select the first row, it subtracts the amount instead of adding it; after a row is selected, if I tap on the back button and then come back to same screen the checkmark is not displayed.
In this construct when I try to retrieve from NSUserDefaults indexPathForCellSelected
evaluates to nil even though I check if indexPathForCellSelected != nil
before making the assignment.
fatal error: unexpectedly found nil while unwrapping an Optional value
if indexPathForCellSelected != nil { self.tableView.cellForRowAtIndexPath(indexPathForCellSelected!)?.
accessoryType = .Checkmark
}
class NinethViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
var total = 0
var indexRowRetrieved:Int?
var rowSelected:Int?
var indexRowSelectedKey = "indexRowKey"
var amountKey = "amountKey"
var totalKey = "totalKey"
let indexPathKey = "indexPathForCellSelected"
var indexPathForCellSelected: NSIndexPath?
struct Item {
var name:String // name of the row
var selected:Bool // whether is selected or not
var amount: Int // value of the item
}
var extras = [
Item(name:"Inside Cabinets",selected: false, amount: 5),
Item(name:"Inside Fridge",selected: false, amount: 5),
Item(name:"Inside Oven",selected: false, amount: 5),
Item(name:"Laundry wash & dry",selected: false, amount: 10),
Item(name:"Interior Windows", selected: false, amount: 5)
]
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// loadData from NSUserDefaults
loadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return extras.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
// configure the cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
cell?.textLabel?.text = extras[indexPath.row].name
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// if the cell has not been selected before
if !extras[indexPath.row].selected {
// marks the cell as selected
extras[indexPath.row].selected = true
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
self.total += extras[indexPath.row].amount
indexPathForCellSelected = indexPath
rowSelected = indexPath.row
print(total)
// save all info in NSUserDefaults
saveData()
} else {
// marks the cell as not selected
extras[indexPath.row].selected = false
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .None
self.total -= extras[indexPath.row].amount
print(total)
}
}
func saveData(){
// save indexPathForCellSelected in NSUserDefaults
if indexPathForCellSelected != nil {
let data = NSKeyedArchiver.archivedDataWithRootObject(indexPathForCellSelected!)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: indexPathKey)
// save indexRowSelected
NSUserDefaults.standardUserDefaults().setInteger(rowSelected!, forKey: indexRowSelectedKey)
// save amount for corresponding row in NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(extras[rowSelected!].amount, forKey: amountKey)
//save total in NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(total, forKey: totalKey)
}
}
func loadData() {
//retrieve indexPathForCellSelected from NSUserDefaults
if let retrievedIndexPath = NSUserDefaults.standardUserDefaults().dataForKey(indexPathKey) {
if let data1 = NSKeyedUnarchiver.unarchiveObjectWithData(retrievedIndexPath) as? NSIndexPath{
indexPathForCellSelected = data1
}
}
// retrieve the index for row selected to select the state of the row: true or false
if let retrievedIndexRow = NSUserDefaults.standardUserDefaults().integerForKey(indexRowSelectedKey) as? Int {
indexRowRetrieved = retrievedIndexRow
extras[retrievedIndexRow].selected = true
}
// retrieve amount for corresponding row in NSUserDefaults
if let itemAmount = NSUserDefaults.standardUserDefaults().objectForKey(amountKey) as? Int {
extras[indexRowRetrieved!].amount = itemAmount
// assign checkmark to row selected
if indexPathForCellSelected != nil {
self.tableView.cellForRowAtIndexPath(indexPathForCellSelected!)?.accessoryType = .Checkmark
}
}
// retrieve total from NSUserDefaults
if let totalRetrieved = NSUserDefaults.standardUserDefaults().objectForKey(totalKey) as? Int {
total = totalRetrieved
print(total)
}
}
}
推荐答案
我不知道为什么当您根据上一个问题和这个问题来保存先前选择的单元格的所有NSIndexPath
时,您需要仅保存所选单元格的索引以及转到另一个控制器时所拥有的总数的值.您可以通过以下方式进行操作:
I don't know why you are saving all the NSIndexPath
's for the cells selected previously when according your previous question and this one, you need to save only the index of the cell selected and the value of the total you had when you go to another controller. You can do it in the following way:
var frequency = [
Item(name:"Every week",selected: false, amount: 30),
Item(name:"Every 2 weeks",selected: false, amount: 30),
Item(name:"Every 4 weeks",selected: false, amount: 30),
Item(name:"Once",selected: false, amount: 40),
Item(name:"End of tenancy cleaning", selected: false, amount: 44)
]
var indexPathForCellSelected: NSIndexPath?
var total = 0
let indexPathKey = "indexPathForCellSelectedNinethViewControllerKey"
let totalKey = "totalNinethViewControllerKey"
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.textLabel?.text = frequency[indexPath.row].name
if let _ = indexPathForCellSelected where indexPath == indexPathForCellSelected {
cell.accessoryType = .Checkmark
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if !frequency[indexPath.row].selected {
// this avoid set initial value for the first time
if let index = indexPathForCellSelected {
// clear the previous cell
frequency[index.row].selected = false
tableView.cellForRowAtIndexPath(index)?.accessoryType = .None
self.total -= frequency[index.row].amount
}
// mark the new one
frequency[indexPath.row].selected = true
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
indexPathForCellSelected = indexPath
self.total += frequency[indexPath.row].amount
saveData()
}
}
private func saveData() {
// save the index for the cell selected in NSUserDefaults
NSUserDefaults.standardUserDefaults().setInteger(indexPathForCellSelected!.row, forKey: indexPathKey)
// save total in NSUserDefaults
NSUserDefaults.standardUserDefaults().setInteger(total, forKey: totalKey)
}
private func loadData() {
// get the values from NSUserDefaults if exist
if let indexValue = NSUserDefaults.standardUserDefaults().valueForKey(indexPathKey), totalValue = NSUserDefaults.standardUserDefaults().valueForKey(totalKey) {
indexPathForCellSelected = NSIndexPath(forRow: indexValue as! Int, inSection: 0)
total = totalValue as! Int
}
}
希望这对您有所帮助.
这篇关于尝试保存到NSUserdefaults时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!