UITableView 中的 NSUserDefaults 和持久性

Posted

技术标签:

【中文标题】UITableView 中的 NSUserDefaults 和持久性【英文标题】:NSUserDefaults and persistency in a UITableView 【发布时间】:2016-12-01 19:28:25 【问题描述】:

我有一个快速编码问题。首先,我使用的是 XCode 8 和 swift 2。这是我的视图控制器的快速图像,因此您可以获得更好的想法。 Image of my viewcontroller

在上图中,您插入一个目标(文本到文本字段)并按提交。提交按钮(“提交目标”)将文本字段中的文本插入到数组中。这个数组然后显示在表格视图中。

我的问题是,如何在此视图控制器中实现 NSUserDefualts 以保存数组?如果用户从 tableview 中删除目标之一,这也需要能够更新数组。

这是我目前的视图控制器代码:

//
//  VCWeeklyGoals.swift
//  FitNote
//
//  Created by ---- on 9/21/16.
//  Copyright © 2016 Haiden Stiles. All rights reserved.
//

import UIKit

class VCWeeklyGoals: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate 

    //MARK: Properties








//DATE AND TIME
@IBOutlet weak var labelDate: UILabel!
var timer = NSTimer()

@objc func tick() 
    labelDate.text = NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .MediumStyle, timeStyle: .MediumStyle)

//END DATE AND TIME

//BEGINNING ROUNDED BUTTONS FOR MONDAY THROUGH FRIDAY
//@IBOutlet weak var roundedButtonMonday: UIButton!


    //ROUNDED BUTTON FOR SUBMIT GOAL
@IBOutlet weak var roundedButtonSubmitGoal: UIButton!
    //END ROUNDED BUTTON FOR SUBMIT GOAL

//END ROUNDED BUTTONS FOR MONDAY THROUGH FRIDAY







//BEGINNING OF TABLE FUNCTIONS AND PROPERTIES

@IBOutlet var tableView: UITableView!
@IBOutlet var insertedGoal: UITextField!

//var tableTitles = NSUserDefaults.standardUserDefaults().arrayForKey("tableTitles") as! [String]
var tableTitles = [String]()




@IBAction func buttonSubmitGoal(sender: UIButton) 

    self.view.endEditing(true)

    var error = ""

    if insertedGoal.text == "" 

        error = "Please enter a goal!"
     else 

        tableTitles.append(insertedGoal.text!)
        self.tableView.reloadData()
    

    if error != "" 

        let alert = UIAlertController(title:"Error In Form", message: error, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title:"OK", style: .Default, handler:  action in

            //self.dismissViewControllerAnimated(true, completion:nil)

        ))

        self.presentViewController(alert, animated:true, completion:nil)

    

    insertedGoal.text = ""





//func numberOfSectionsInTableView(tableView: UITableView) -> Int 
//    return 1
//


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return tableTitles.count


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

    let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell

    let object = tableTitles[indexPath.row] 
    cell.textLabel!.text = object

    return cell


func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
    if editingStyle == UITableViewCellEditingStyle.Delete 
        tableTitles.removeAtIndex(indexPath.row)
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    


//END OF TABLE FUNCTIONS AND PROPERTIES



//OVERRIDE FUNCTIONS

override func viewDidLoad() 
    super.viewDidLoad()



    if let temp = NSUserDefaults.standardUserDefaults().objectForKey("tableTitles") as? [String] 
        tableTitles = temp
    


    // Do any additional setup after loading the view.

    //TABLE PROPERTIES
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")

    self.insertedGoal.delegate = self
    tableView.delegate = self
    tableView.dataSource = self
    //END TABLE PROPERTIES

    //DATE PROPERTIES
    timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
        target: self,
        selector: #selector(tick),
        userInfo: nil,
        repeats: true)
    //END DATE PROPERTIES

    //ROUNDED BUTTON FOR MONDAY THROUGH FRIDAY PROPERTIES
    //MONDAY
    //roundedButtonMonday.backgroundColor = UIColor.whiteColor()
    //roundedButtonMonday.layer.cornerRadius = 6
    //roundedButtonMonday.layer.borderWidth = 0.5
    //roundedButtonMonday.layer.borderColor = UIColor.blueColor().CGColor


        //ROUNDED BUTTON FOR SUBMIT GOAL
    roundedButtonSubmitGoal.backgroundColor = UIColor.clearColor()
    roundedButtonSubmitGoal.layer.cornerRadius = 7
    roundedButtonSubmitGoal.layer.borderWidth = 1
    roundedButtonSubmitGoal.layer.borderColor = UIColor.blueColor().CGColor

        //END ROUNDED BUTTON FOR SUBMIT GOAL
    //END ROUNDED BUTTON FOR MONDAY THROUGH FRIDAY PROPERTIES

    //DATE PICKER

    //END DATE PICKER


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.



【问题讨论】:

不要使用NSUserDefaults来保存数据。那不是它的目的。使用NSArray 的方法将数组写入文件。 我正在研究 NSArray,但我觉得我在这方面没有取得任何进展......你介意指导我朝着正确的方向实施 NSArray 吗? 【参考方案1】:

我一直在处理您的问题,这是我的解决方案

首先我为目标创建一个模型,是一个简单的模型,只有目标的文本,还有两个静态方法,一个用于保存,另一个用于加载

class Goal: NSObject 

var text : String = ""

init(text: String) 
    super.init()
    self.text = text


static func loadFromFile(fileName:String) ->[Goal]?

    let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true);
    let docsDirectory = paths[0];
    let path = docsDirectory + "/" + fileName;
    let data = NSArray(contentsOfFile: path);

    if(data != nil)
    
        var returnArray : [Goal] = []
        for object in data! 
            returnArray.append(Goal(text: object as! String))
        
        return returnArray
    

    return nil


static func saveToPlist(filename:String,goals:[Goal]) -> Bool 

    let toSaveArray = NSMutableArray();
    for goal in goals 
        toSaveArray.add(goal.text)
    

    let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true);
    let docsDirectory = paths[0];
    let path = docsDirectory + "/" + filename;
    return toSaveArray.write(toFile: path, atomically: true);



这是我在 ViewController 上的实现,GoalTableViewCell 是一个简单的单元格,只有一个 UILabel

import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource 

@IBOutlet weak var tfGoalTextAdd: UITextField!
@IBOutlet weak var btnAdd: UIButton!
@IBOutlet weak var tableView: UITableView!
var goals : [Goal] = []
override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    self.tableView.estimatedRowHeight = 40;
    self.loadGoals()
    self.btnAdd.addTarget(self, action: #selector(addGoalWithTextFieldText), for: .touchUpInside)


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


public func loadGoals()

    if let arrayGoals = Goal.loadFromFile(fileName: "goals")
    
        self.goals = arrayGoals
    


public func addGoalWithTextFieldText()

    if(self.tfGoalTextAdd.text != nil && self.tfGoalTextAdd.text != "")
    
        self.addGoal(text: self.tfGoalTextAdd.text!)
        self.tfGoalTextAdd.text = ""
    


public func addGoal(text: String)

    self.goals.append(Goal(text: text))
    self.tableView.reloadData()
    if(Goal.saveToPlist(filename: "goals", goals: goals))
    
        debugPrint("Successful saved")
    


public func removeGoal(goal:Goal)

    goals.remove(at:goals.index(of: goal)!)
    self.tableView.reloadData()
    if(Goal.saveToPlist(filename: "goals", goals: goals))
    
        debugPrint("Successful saved")
    



public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

    return self.goals.count



public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return UITableViewAutomaticDimension


// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

    let cell = tableView.dequeueReusableCell(withIdentifier: "GoalCell") as! GoalTableViewCell
    cell.setupWithGoal(goal: self.goals[indexPath.row])
    return cell



public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool 
    return true



public func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle 
    return .delete


public func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) 
    if editingStyle == .delete 
        // Delete the row from the data source

        //tableView.beginUpdates()
        self.removeGoal(goal: self.goals[indexPath.row])

        //tableView.endUpdates()

     else if editingStyle == .insert 
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    




希望对你有帮助

【讨论】:

以上是关于UITableView 中的 NSUserDefaults 和持久性的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollview 中的 UIView 中的 UITableView :点击时 UITableView 数据被清除

为啥第一次滚动到另一个 UITableView 中的 UICollectionView 中的 UITableView 不加载数据?

水平 UITableView 中的垂直 UITableView

在 UITableView 中的 UINib 中重新加载 UITableView

尝试在用户向 iOS 中的 UITableView 添加行时动态增加 UITableView 的高度

UIViewController 中的 UITableView