2016-12-05 208 views
4

我目前正在快速地尝试持久数据,但我无法保存这些数据并重新找回它。基本上我有两个文本字段,当用户按下提交按钮时,条目将被保存到UITable中,在这里用户将能够移动表中的条目或者如果他们希望删除它们。我的主要问题是保存和加载这些数据。Swift中的持久数据

Taskmanager.swift - 在这里,我有我的基本类型的存储

import Foundation 

import UIKit 

var taskMgr: TaskManager = TaskManager() 

struct task { 
    var name = "Name" 
    var year = "Year" 
} 


//setting data 
let defaults = UserDefaults.standard 
//defaults.synchronize() 


//getting data 

class TaskManager: NSObject { 
    var tasks = [task]() 

    func addTask(name: String, year: String){ 
     tasks.append(task(name: name, year: year)) 
    } 
} 

ThirdViewController.swift - 在这里,我有我的存储表和它的功能,我也有保存和载入数据功能的草图。

import Foundation 

import UIKit 

class ThirdViewController:UIViewController, UITableViewDelegate, UITableViewDataSource { 

    @IBOutlet var tableView: UITableView! 

    @IBAction func deleteT(_ sender: Any) { 

     if(tableView.isEditing == true){ 
     tableView.setEditing(false, animated: true) 
     }else{ 
     tableView.setEditing(true, animated: true) 
     } 


    } 

    func saveData() { 

     let data = NSMutableData() 

     let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) 
     let path = paths[0] 
     let file = (path as NSString).appendingPathComponent("Persistent.plist") 

     //2 
     let archiver = NSKeyedArchiver(forWritingWith: data) 
     archiver.encode(G, forKey: "name") 
     archiver.endode(year, forKey: "year") 
     archiver.finishEncoding() 
     data.write(toFile: file, atomically: true) 
    } 


    func loadData() { 
     let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) 
     let path = paths[0] 
     let file = (path as NSString).appendingPathComponent("Persistent.plist") 

     // 1 
     if FileManager.default.fileExists(atPath: file) { 
      if let data = NSData(contentsOfFile: file) { 
       let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data) 
       name = unarchiver.decodeObjectForKey("name") as! [String] 
       year = unarchiver.decodeObjectForKey("year") as! [String] 


       unarchiver.finishDecoding() 
      } 
     } 
    } 





    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { 
     return true 
    } 

    func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool { 
     return false 
    } 

    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) { 


    } 

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 
     return true 
    } 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     tableView.reloadData() 
     loadData() 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     self.tableView.reloadData() 
    } 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ 
     return taskMgr.tasks.count 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{ 

     let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "TableView") 

     //Assign the contents of our var "items" to the textLabel of each cell 
     cell.textLabel!.text = taskMgr.tasks[indexPath.row].name 
     cell.detailTextLabel!.text = taskMgr.tasks[indexPath.row].year 
     //cell.editing = tableView(tableView, canMoveRowAtIndexPath: indexPath) 

     return cell 

    } 

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){ 
     if (editingStyle == UITableViewCellEditingStyle.delete){ 

      taskMgr.tasks.remove(at: indexPath.row) 
      tableView.reloadData() 
     } 
    } 
} 

FourthViewController.swift - 在这里,我有我的文本框和按钮,我如何将我的条目表。

import Foundation 

import UIKit 

class FourthViewController: UIViewController, UITextFieldDelegate{ 

    @IBOutlet var addT: UITextField! 
    @IBOutlet var addY: UITextField! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 
    } 

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


    @IBAction func confTask(_ sender:UIButton){ 
     if (addT.text == ""){ 
     }else{ 
     //add record 
     let name: String = addT.text! 
     let Year: String = addY.text! 
     //taskMgr.addTask(name:name) 
     taskMgr.addTask(name:name, year:Year) 

     } 

     //dismiss keyboard and reset fields 

     self.view.endEditing(true) 
     addT.text = nil 
     addY.text = nil 

    } 

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
     self.view.endEditing(true) 
    } 

    func textFieldShouldReturn(_ textField: UITextField) -> Bool{ 
     textField.resignFirstResponder() 
     return true 
    } 





} 
+0

检查这个http://stackoverflow.com/questions/40756178/how-can-i-delete-object-from-core -data-in-swift-3/40756625#40756625,可能是你得到你的解决方案 –

+0

感谢您的快速响应,但我试图将数据添加到plist文件(不一定是plist,但我认为这是最简单的方式?),并从那里检索它,一旦我关闭它。我没有完全理解你的答案,我将如何操作它来与我的工作?谢谢! –

+0

其实我给你的是核心数据参考 –

回答

1

我已经使用NSUserDefaults创建了一些示例代码来保持任务。这是一个相当简单的例子,只要你只是试验,只想少于100个元素,应该没问题。使用下面的代码你应该能够显示,删除和保存任务。

但是,在未来,我强烈建议您阅读Core Data。有很多很棒的教程,像这样的one

我已经创建了一个Task对象模型和TaskManager用于读取,保存和删除任务。

import Foundation 

// Task Data Model 
class Task: NSObject, NSCoding { 
    let name: String 
    let year: String 

    required init(name: String, year: String) { 
     self.name = name 
     self.year = year 
    } 

    required init(coder decoder: NSCoder) { 
     self.name = decoder.decodeObject(forKey: "name") as? String ?? "" 
     self.year = decoder.decodeObject(forKey: "year") as? String ?? "" 
    } 

    func encode(with coder: NSCoder) { 
     coder.encode(name, forKey: "name") 
     coder.encode(year, forKey: "year") 
    } 
} 

class TaskManager { 
    /// UserDefaults instance 
    private let defaults = UserDefaults.standard 

    /// Singleton instance, class **should** be accessed by this property 
    static let shared = TaskManager() 

    /// Indetifier of tasks container in `defaults` 
    private let kTasksIdentifier = "tasks" 

    /// Add a new task to your container and syncronize it into `defaults` 
    /// 
    /// - Parameters: 
    /// - name: Name of the task 
    /// - year: Year of the task 
    func save(taskName name: String, year: String) { 
     let task = Task(name: name, year: year) 

     // Check if there is already saved tasks 
     guard let data = defaults.value(forKey: kTasksIdentifier) as? Data, var tasks = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Task] else { 
      // If not, save it as the first one 
      syncronizeTasks(tasks: [task]) 
      return 
     } 

     tasks.append(task) 
     syncronizeTasks(tasks: tasks) 
    } 

    /// Remove a task at an index 
    /// 
    /// - Parameters: 
    /// - index: The index of the removeable task 
    func remove(at index: Int) { 

     guard let data = defaults.value(forKey: kTasksIdentifier) as? Data, var tasks = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Task] else { 
      fatalError("Unable to retrive tasks from defaults") 
     } 

     tasks.remove(at: index) 
     syncronizeTasks(tasks: tasks)   
    } 

    /// Read all tasks elements 
    /// If there are tasks in memory, it returns the one from memory 
    /// Otherwise reads it from `UserDefaults` 
    /// 
    /// - Returns: all tasks elements available, return empty array if no elements found 
    func readAllTasks() -> [Task] { 
     let data = UserDefaults.standard.value(forKey: kTasksIdentifier) 
     let allTasks = NSKeyedUnarchiver.unarchiveObject(with: data as! Data) 
     return allTasks as? [Task] ?? [Task]() 
    } 


    private func syncronizeTasks(tasks: [Task]) { 
     let data = NSKeyedArchiver.archivedData(withRootObject: tasks) 
     defaults.set(data, forKey: kTasksIdentifier) 
     defaults.synchronize() 
    } 
} 

我已经修改了您已有的ThirdViewController了一下。

import UIKit 
import Foundation 

class ThirdViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 

    @IBOutlet var tableView: UITableView! 
    /// Your tasks being updated in this collection every time `refreshTasks()` is being called 
    private var tasks = [Task]() 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 
     self.refreshTasks() 
     self.tableView.reloadData() 
    } 

    func refreshTasks() { 
     self.tasks = TaskManager.shared.readAllTasks() 
    } 

    @IBAction func deleteT(_ sender: Any) { 
     if(tableView.isEditing == true) { 
      tableView.setEditing(false, animated: true) 
     } else { 
      tableView.setEditing(true, animated: true) 
     } 
    } 

    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { 
     return true 
    } 

    func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool { 
     return false 
    } 

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

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ 
     return tasks.count 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{ 

     let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "TableView") 

     //Assign the contents of our var "items" to the textLabel of each cell 
     cell.textLabel!.text = tasks[indexPath.row].name 
     cell.detailTextLabel!.text = tasks[indexPath.row].year 
     //cell.editing = tableView(tableView, canMoveRowAtIndexPath: indexPath) 

     return cell 

    } 

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){ 
     if (editingStyle == UITableViewCellEditingStyle.delete) { 
      self.tableView.beginUpdates() 
      TaskManager.shared.remove(at: indexPath.row) 
      refreshTasks() 
      self.tableView.deleteRows(at: [indexPath], with: .fade) 
      self.tableView.endUpdates() 
     } 
    } 
} 

而且,为了以防万一,编辑了自己的FourthViewController

import Foundation 
import UIKit 

class FourthViewController: UIViewController, UITextFieldDelegate { 

    @IBOutlet var addT: UITextField! 
    @IBOutlet var addY: UITextField! 

    /// User has pressed `Submit` button 
    /// 
    /// - Parameter sender: the pressed button 
    @IBAction func confTask(_ sender: UIButton) { 
     // Check if textfields are containing text 
     guard let nameText = addT.text, let yearText = addY.text, !nameText.isEmpty, !yearText.isEmpty else { 
      print("at least one of the textFields is not filled") 
      return 
     } 

     // Save the tasks 
     TaskManager.shared.save(taskName: nameText, year: yearText) 

     //dismiss keyboard and reset fields 
     self.view.endEditing(true) 
     addT.text = nil 
     addY.text = nil 
    } 

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
     self.view.endEditing(true) 
    } 

    func textFieldShouldReturn(_ textField: UITextField) -> Bool{ 
     textField.resignFirstResponder() 
     return true 
    } 
}