All about TableViews

Sept 20, 2017   3 minutes to read



Part 3: Saving Elements

In part 1 we learned how to populate a table view and after part 2 we were also able to add new entries from the users input. However, the new entries were only visible during the runtime of the app. In this part we will take a closer look on how we can save the entries, such that they are still visible whenever the app is restarted.

1
First we create a new Swift File by right clicking on the "Project Folder" inside the "Project Navigator" and then selecting "New File.." and afterwards choosing "Swift File". We will name this file "Employee". Inside the Employee.swift file we are going to create a Class Employee as follows:
import Foundation

class Employee: NSObject, NSCoding {
    
    // Similar to classes, you can have classes inside of classes
    struct Keys {
        static let Name = "name"
        static let LastName = "lastName"
        // If not static, you would need to create a Object e.g var s = Keys()
        // .. and access the name by typing "s.Name"
        // WITH static you can simply get it by typing: "Keys.Name"
    }
    
    // Private Variables
    private var _name = ""
    private var _lastname = ""
    
    override init() {}
    
    // Saving: Encodes our Objects -> Saving As KeyValue Pair, therefore Struct Keys
    func encode(with aCoder: NSCoder) {
        // encode object for key
        aCoder.encode(_name, forKey: Keys.Name)
        aCoder.encode(_lastname, forKey: Keys.LastName)
    }
    
    // Loading : Decodes our Objects
    required init?(coder aDecoder: NSCoder) {
        
        if let nameObj = aDecoder.decodeObject(forKey: Keys.Name) as? String{
            _name = nameObj
        }
        
        if let lastNameObj = aDecoder.decodeObject(forKey: Keys.LastName) as? String{
            _lastname = lastNameObj
        }
        
    }
    
    // Our own initializer
    init(name: String, lastName: String){
        self._name = name
        self._lastname = lastName
    }
    
    // Getters and Setters
    var Name: String {
        get{
            return _name
        }
        set{
            _name = newValue
        }
    }
    
    var LastName: String {
        get{
            return _lastname
        }
        set{
            _lastname = newValue
        }
    }
}


2
Now we change the ViewController.swift to:
import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    @IBOutlet weak var myTableView: UITableView!
    
    var data = [Employee]()

    override func viewDidLoad() {
        super.viewDidLoad()
        loadData()
        print("THE DATA IS STORED AT: \(filePath)")
    }
    
    // Save File Path
    var filePath: String {
        let manager = FileManager.default
        let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
        return url!.appendingPathComponent("Data").path
    }
    
    private func loadData(){
        if let ourData = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? [Employee]{
            data = ourData
        }
    }
    
    private func saveData(employee: Employee){
        data.append(employee)
        NSKeyedArchiver.archiveRootObject(data, toFile: filePath)
    }
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier:
        "Cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row].Name
        cell.detailTextLabel?.text = data[indexPath.row].LastName
        
        return cell
    }
    
    @IBAction func addEmployee(_ sender: UIBarButtonItem) {
        let alert = UIAlertController(title: "Add Employee", message: "Enter firstname and lastname", preferredStyle: .alert)
        
        alert.addTextField(configurationHandler: nil)
        alert.addTextField(configurationHandler: nil)
        
        alert.addTextField { (textField) in
            textField.placeholder = "Ex: Placeholder with numberKeyboard"
            textField.keyboardType = .numberPad
        }
        
        let save = UIAlertAction(title: "Save", style: .default){
            (alertAction: UIAlertAction) in
            
            let employeeObj = Employee()
            
            if let textField1 = alert.textFields?[0].text{
                employeeObj.Name = textField1
                self.myTableView.reloadData()
            }
            
            if let textField2 = alert.textFields?[1].text{
                employeeObj.LastName = textField2
                self.myTableView.reloadData()
            }
            
            self.saveData(employee: employeeObj)
            self.myTableView.reloadData()
            
            
        }
        
        let cancel = UIAlertAction(title: "Cancel", style: .default, handler: nil)
        
        alert.addAction(save)
        alert.addAction(cancel)

        self.present(alert, animated: true, completion: nil)
        
    }
    
    
}