Fernando
Fernando

Reputation: 460

Data won't load into my Table View

So I have a UITableViewController class for my notes app where everything is working fine, adding, deleting, and editing of the table view. But now I'm trying to load the data using "Realm" Database. I'm fairly new to iOS (Swift) and especially Realm, so I'm kind of confused. I got it to save into the database perfectly, and it shows up when I click the "Save" button in my navigation bar. But when I restart the app, the table view is completely empty. I've been stuck on this for a while now, tried everything I know so far, but just can not get it to show up whatsoever. Can someone help me out, and maybe tell me what I'm doing wrong, or not doing at all? Thank You very much.

Here is my class as well

import UIKit
import Realm

class NoteTableViewController: UITableViewController {

    // MARK: Properties

    var notes = [Note]() // Initialized with a default value (an empty array of Note objects).

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get Realm Database location
        println(RLMRealm.defaultRealm().path)

    }

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

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // Return the number of sections.
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return notes.count
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // Table view cells are reused and should be dequeued using a cell identifier.
        let cellIdentifier = "NoteTableViewCell"
        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! NoteTableViewCell

        // Fetches the appropriate note for the data source layout in the notes array
        let note = notes[indexPath.row]

        // Configure the cell...
        cell.titleLabel.text = note.title
        cell.bodyLabel.text = note.body

        return cell
    }



    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return NO if you do not want the specified item to be editable.
        return true
    }



    // Override to support editing the table view.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            // Delete the row from the data source
            notes.removeAtIndex(indexPath.row)

            // Get the default Realm (Will do this part later)
            /*
            let realm = RLMRealm.defaultRealm()
            realm.beginWriteTransaction()

            realm.deleteObject(notes[Int(indexPath.row)])
            realm.commitWriteTransaction()
            */

            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        } 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
        }
    }


    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "ShowDetail" { // Clicked on a cell
            let noteDetailViewController = segue.destinationViewController as! NoteViewController
            // Get the cell that generated this segue.
            if let selectedNoteCell = sender as? NoteTableViewCell {
                let indexPath = tableView.indexPathForCell(selectedNoteCell)!
                let selectedNote = notes[indexPath.row]
                noteDetailViewController.note = selectedNote
            }
        }
        else if segue.identifier == "AddItem" { // Clicked add button
            println("Adding new note")
        }
    }


    @IBAction func unwindToNoteList(sender: UIStoryboardSegue) {
        if let sourceViewController = sender.sourceViewController as? NoteViewController, note = sourceViewController.note {
            if let selectedIndexPath = tableView.indexPathForSelectedRow() { // User clicked on a row
                // Update an existing note.
                notes[selectedIndexPath.row] = note

                tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None)
            }
            else {
                // Add a new note.
                let newIndexPath = NSIndexPath(forRow: notes.count, inSection: 0)
                notes.append(note)

                // Persist in database
                let realm = RLMRealm.defaultRealm()
                realm.beginWriteTransaction()
                Note.createInRealm(realm, withValue: notes[newIndexPath.row])
                realm.commitWriteTransaction()

                tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)
            }
        }
    }

}

And this one is the Note Object class

import UIKit // Automatically imports Foundation
import Realm

class Note: RLMObject {

    // MARK: Properties

    dynamic var title: String = ""
    dynamic var body: String = ""

    // MARK: Initialization

    init?(title: String, body: String) { // Failable initializer


        // Initialize stored properties.
        self.title = title
        self.body = body

        super.init()

        // Initialization should fail if there is no title
        if title.isEmpty {
            return nil
        }

    }

    // Must have for Realm to work
    override init() {
        super.init()
    }

}

Solved it after a good 2 more days...Here is my updated class

Did as Swinny89 said, and started with a new notes object, of all objects, instead of initializing an "empty" notes array.

import UIKit
import Realm

class NoteTableViewController: UITableViewController {

  // MARK: Properties

    var notes = Note.allObjects()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get Realm Database location
        println(RLMRealm.defaultRealm().path)

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

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // Return the number of sections.
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return Int(notes.count)
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // Table view cells are reused and should be dequeued using a cell identifier.
        let cellIdentifier = "NoteTableViewCell"
        let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! NoteTableViewCell

        let object = notes[UInt(indexPath.row)] as! Note

        // Configure the cell...
        cell.titleLabel.text = object.title
        cell.bodyLabel.text = object.body

        return cell
    }

    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return NO if you do not want the specified item to be editable.
        return true
    }

    // Override to support editing the table view.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {

            // Delete from database
            let realm = RLMRealm.defaultRealm()
            realm.beginWriteTransaction()
            realm.deleteObject(notes[UInt(indexPath.row)] as! RLMObject)
            realm.commitWriteTransaction()

            // Delete row from table view
            tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        } 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
        }
    }

    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "ShowDetail" { // Clicked on a cell
            let noteDetailViewController = segue.destinationViewController as! NoteViewController
            // Get the cell that generated this segue.
            if let selectedNoteCell = sender as? NoteTableViewCell {
                let indexPath = tableView.indexPathForCell(selectedNoteCell)!

                let selectedNote = notes[UInt(indexPath.row)] as! Note
                noteDetailViewController.note = selectedNote

            }
        }
        else if segue.identifier == "AddItem" { // Clicked add button
            println("Adding new note")
        }
    }

    @IBAction func unwindToNoteList(sender: UIStoryboardSegue) {
        if let sourceViewController = sender.sourceViewController as? NoteViewController, note = sourceViewController.note {

            let uuid = NSUUID().UUIDString // Needed for primary key. see below

            var unwindedNote = Note()

            if let selectedIndexPath = tableView.indexPathForSelectedRow() { // User clicked on a row

                // Updating of the note is done in NoteViewController

                tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None)
            }
            else {
                // Add a new note.
                let newIndexPath = NSIndexPath(forRow: Int(notes.count), inSection: 0)

                // Persist in database
                let realm = RLMRealm.defaultRealm()
                realm.beginWriteTransaction()

                unwindedNote.title = note.title
                unwindedNote.body = note.body
                unwindedNote.id = uuid // This is done for the primary key that Realm needs, unique for each object created.

                realm.addObjects([unwindedNote])
                realm.commitWriteTransaction()

                tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)
            }
        }
    }
}

Upvotes: 1

Views: 2067

Answers (1)

Swinny89
Swinny89

Reputation: 7373

This is because your Note array is initialised as an empty array and that's what you are using to tell the tableView how many rows there are, which is 0.

Once your Note array has been set and has some data you can then call tableView.reloadData() to reload the array with the data.

Also, looking at the code above, your class is inheriting from UITableViewController rather than implementing UITableViewControllerDelegate and UITableViewControllerDataSource. Once your class implements these you need to make sure that you set the viewController as the datasource and delegate for the tableViewController either in the storyboard or through code.

Upvotes: 2

Related Questions