尝试保存到NSUserdefaults时出错 [英] Error when trying to save to NSUserdefaults

查看:82
本文介绍了尝试保存到NSUserdefaults时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表,其工作方式如下.如果选择了一行,则将与所选行相对应的数量添加到var total,并添加一个选中标记.如果取消选择,则将减去金额,复选标记将被设置为none. 在尝试将数据保存到NSUserDefaults或从NSUserDefaults检索数据之前,我的代码正常工作. 错误是:当我选择第一行时,它减去了金额而不是加了;选定一行后,如果我点击后退"按钮,然后返回到同一屏幕,则不会显示选中标记. 在此构造中,当我尝试从NSUserDefaults检索时,即使我在进行赋值之前检查了if indexPathForCellSelected != nilindexPathForCellSelected的计算结果仍为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆