Display The Records Added Into The Database On Tableview

In my last article, we learned the Create/Insert operation.So now, we will move to the second step of CRUD operations; i.e Read/Display the added records on our UI.
 
For my last article about inserting records into the database, please refer to the link.
 
In my last article, we had created a UI which takes Name, Age and Phone Number as input and inserts the record into our database. We had performed this operation using Core Data Framework. So let's continue to the next operation.
  • Open the project  in which you have implemented the Create/Insert operation in Xcode. In my project, I want the records inserted in the database to be displayed on a table. So, I am going to add a tableview on my UI.
  • Open Main.storyboard. Drag and drop a UITableView to your UI. 
  • On the top of the view controller, you can see 3 icons - View Controller, First Responder and Exit. Select the tableView, press Ctrl button and with the Ctrl button pressed, drag the mouse towards the yellow icon on the top of the ViewController. Once you select the yellow icon, a black box appears. Select 'dataSource'  from the black box.
  • Repeat the above step and this time, select 'delegate' from the black box. If you see the white dots as shown in the below image, that means you have selected them.
         
  • Note: Connecting the tableview to datasource and delegate on UI is important. If you miss this step, your data will not be displayed. 
  • Now, connect your tableview outlet to your ViewController using Assistant.
  • Now, we need to create a tableview cell for our tableview. Right-click on your Project Folder and select New File.
  • Select iOS -> Cocoa Touch Class and click Next.
  • Select UITableviewCell for SubClass of: and name your file. Also, select the checkbox 'Also create XIB File' and select the language as Swift. Click on Next and click on Create.
   
  • This will add 2 new files to your project, an XIB file and a Swift File.
  • Open the .xib file. Select the TableView Cell and assign an Identifier to this cell in its Attributes Inspector. I have assigned the Identifier as 'details'.
  • Add 3 Labels inside the TableViewCell.
  • Connect the labels to the .Swift file that you had created with this .xib file using the Assistant.
  • Your  .Swift file will contain the below code.
    1. import UIKit  
    2. class DetailsTableViewCell: UITableViewCell {  
    3.     @IBOutlet weak  
    4.     var tblLblPhoneNo: UILabel!@IBOutlet weak  
    5.     var tblLblAge: UILabel!@IBOutlet weak  
    6.     var tblLblName: UILabel!override func awakeFromNib() {  
    7.         super.awakeFromNib()  
    8.         // Initialization code  
    9.     }  
    10.     override func setSelected(_ selected: Bool, animated: Bool) {  
    11.         super.setSelected(selected, animated: animated)  
    12.         // Configure the view for the selected state  
    13.     }  
    14. }  
  • Now we will add the code to display our data on our tableview.
  • Open ViewController and add UITableViewDelegate and UITableViewDataSource to the line class ViewController: UIViewController.
    1. class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {  
  • When you add them, you will get an error, just click on the error and fix them and Xcode will automatically add two functions of tableView.
  • Add the below line in your ViewController.
    1. var details:[NSManagedObject] = []  
  • Now, add the below code in the viewDidLoad() function.
    1. tableView.register(UINib(nibName: "DetailsTableViewCell", bundle: nil), forCellReuseIdentifier: "details")  
  • We add the above code to register our xib. Every time we create an .xib File, we need to register them in our ViewController.
  • Paste the below code after the viewDidLoad() function.
    1. override func viewWillAppear(_ animated: Bool) {  
    2.     super.viewWillAppear(animated)  
    3.     //1  
    4.     guard  
    5.     let appDelegate = UIApplication.shared.delegate as ? AppDelegate  
    6.     else {  
    7.         return  
    8.     }  
    9.     let managedContext = appDelegate.persistentContainer.viewContext  
    10.     //2  
    11.     let fetchRequest = NSFetchRequest < NSManagedObject > (entityName: "Details")  
    12.     //3  
    13.     do {  
    14.         details =  
    15.             try managedContext.fetch(fetchRequest)  
    16.     } catch  
    17.     let error as NSError {  
    18.         print("Could not fetch. \(error), \(error.userInfo)")  
    19.     }  
    20. }  
  • This code fetches the data from the database. NSFetchRequest executes the fetch request using current managed object context.This method must be called from within a block submitted to a managed object context.
  • In the function of Add button, add the line details.append(record) in the do{} block after the line try managedContext.save(). This will add the NSManagedObject data to [NSManagedObject] array.
    1. do{  
    2. try managedContext.save()  
    3. details.append(record)  
  • Paste the below code in the tableView functions that the XCode had automatically added.
    1. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) - > Int {  
    2.     return details.count  
    3. }  
    4. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) - > UITableViewCell {  
    5.     let person = details[indexPath.row]  
    6.     let cell = tableView.dequeueReusableCell(withIdentifier: "details",  
    7.         for: indexPath) as!DetailsTableViewCell  
    8.     cell.tblLblName?.text = (person.value(forKey: "name") ? ? "-") as ? String  
    9.     cell.tblLblAge?.text = String(describing: person.value(forKey: "age") ? ? "-")  
    10.     cell.tblLblPhoneNo?.text = String(describing: person.value(forKey: "phone") ? ? "-")  
    11.     return cell  
    12. }  
  • In the above code, I had added ?? "-" so that if the user does not enter input in any of the fields, then it will display "-" instead of blank field.
  • Overall, the ViewController will contain the code as follows,
    1. import UIKit  
    2. import CoreData  
    3. class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {  
    4.     var details: [NSManagedObject] = []  
    5.     @IBOutlet weak  
    6.     var tableView: UITableView!@IBOutlet weak  
    7.     var txtPhoneNo: UITextField!@IBOutlet weak  
    8.     var txtAge: UITextField!@IBOutlet weak  
    9.     var txtName: UITextField!@IBOutlet weak  
    10.     var lblPhoneNo: UILabel!@IBOutlet weak  
    11.     var lblAge: UILabel!@IBOutlet weak  
    12.     var lblName: UILabel!override func viewDidLoad() {  
    13.         super.viewDidLoad()  
    14.         tableView.register(UINib(nibName: "DetailsTableViewCell", bundle: nil), forCellReuseIdentifier: "details")  
    15.     }  
    16.     override func viewWillAppear(_ animated: Bool) {  
    17.         super.viewWillAppear(animated)  
    18.         //1  
    19.         guard  
    20.         let appDelegate = UIApplication.shared.delegate as ? AppDelegate  
    21.         else {  
    22.             return  
    23.         }  
    24.         let managedContext = appDelegate.persistentContainer.viewContext  
    25.         //2  
    26.         let fetchRequest = NSFetchRequest < NSManagedObject > (entityName: "Details")  
    27.         //3  
    28.         do {  
    29.             details =  
    30.                 try managedContext.fetch(fetchRequest)  
    31.         } catch  
    32.         let error as NSError {  
    33.             print("Could not fetch. \(error), \(error.userInfo)")  
    34.         }  
    35.     }  
    36.     @IBAction func btnAdd(_ sender: Any) {  
    37.         //1  
    38.         guard  
    39.         let appDelegate = UIApplication.shared.delegate as ? AppDelegate  
    40.         else {  
    41.             return  
    42.         }  
    43.         let managedContext = appDelegate.persistentContainer.viewContext  
    44.         //2  
    45.         let entity = NSEntityDescription.entity(forEntityName: "Details"in : managedContext) !  
    46.             //3  
    47.             let record = NSManagedObject(entity: entity, insertInto: managedContext)  
    48.         //4  
    49.         record.setValue(txtName.text, forKey: "name")  
    50.         record.setValue(Int16(txtAge.text!), forKey: "age")  
    51.         record.setValue(Int16(txtPhoneNo.text!), forKey: "phone")  
    52.         do {  
    53.             try managedContext.save()  
    54.             details.append(record)  
    55.             print("Record Added!")  
    56.             //To display an alert box  
    57.             let alertController = UIAlertController(title: "Message", message: "Record Added!", preferredStyle: .alert)  
    58.             let OKAction = UIAlertAction(title: "OK", style: .default) {  
    59.                 (action: UIAlertAction!) in  
    60.             }  
    61.             alertController.addAction(OKAction)  
    62.             self.present(alertController, animated: true, completion: nil)  
    63.         } catch  
    64.         let error as NSError {  
    65.             print("Could not save. \(error),\(error.userInfo)")  
    66.         }  
    67.         self.tableView.reloadData()  
    68.     }  
    69.     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) - > Int {  
    70.         return details.count  
    71.     }  
    72.     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) - > UITableViewCell {  
    73.         let person = details[indexPath.row]  
    74.         let cell = tableView.dequeueReusableCell(withIdentifier: "details",  
    75.             for: indexPath) as!DetailsTableViewCell  
    76.         cell.tblLblName?.text = (person.value(forKey: "name") ? ? "-") as ? String  
    77.         cell.tblLblAge?.text = String(describing: person.value(forKey: "age") ? ? "-")  
    78.         cell.tblLblPhoneNo?.text = String(describing: person.value(forKey: "phone") ? ? "-")  
    79.         return cell  
    80.     }  
    81. }  
  • We have added the code in our project to display our records in our tableview. Lets run the project and test if it works.
  • If everything goes well then we must get the following output.
 
Note
If your application crashes or you do not get the expected output, re-check if you have properly followed the above steps. Here are some of the points that you  may have missed,
  1. Check if you have followed these steps in your Main.storyboard,

    • On the top of the view controller, you can see 3 icons - View Controller, First Responder and Exit. Select the tableView, press Ctrl button and with the Ctrl button pressed, drag the mouse towards the yellow icon on the top of the ViewController. Once you select the yellow icon, a black box appears. Select dataSource option from the black box.
    • Repeat the above step and this time, select delegate option from the black box. If you see the white dots as shown in the below image, that means you have selected them.

  2. Check if you have assigned Identifier to your TableViewCell in the xib file and you have used the same identifier in your code.
  3. Check if you have registered your xib file in your ViewController.
  4. I have noticed that if I give the input of the phone number more than 5-digits then it does not display on my output. This is because we have assigned the data type of phone as Integer16 in our .xcdatamodeld file. You will have to change the data type to Integer32/Integer64/String. If you do so, make sure you delete the existing application from your simulator/iPhone device before running it again otherwise the application will crash. Also make sure, you have made the changes in the code wherever Integer16 was used.
So, we are now successfully able to add our records in our database and display them on the tableview. In my next article, we will perform the remaining 2 CRUD operations - Update and Delete.