forrest
forrest

Reputation: 10992

How do I get new items to display in List View

I am building an app in Xcode 9.4 and I am having trouble getting new items to display in a list view after creating it in another view controller. The item shows up in CoreData, but in order for the item to show in the list view I have to back out of the list view and then return to see it in the list.

I have added the Protocol and Delegate methods but something is still missing from the formula.

Here is the code from the DetailViewController where the new item is added:

import UIKit
import CoreData


protocol DetailViewControllerDelegate: class {
  func detailViewController(_ controller: DetailViewController, didFinishAdding task: Task)
 // func detailViewController(_ controller: DetailViewController, didFinishEditing task: Task)
}

class DetailViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {

  var tasks = [Task]()

  let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

  var selectedTask: String?
  var taskDetails: String?
  var taskCategory: Category?

  @IBOutlet weak var taskTitle: UITextField!
  @IBOutlet weak var taskDetail: UITextView!

  var taskToEdit: Task?

  weak var delegate: DetailViewControllerDelegate? // Required to carry out the protocol methods

    override func viewDidLoad() {
        super.viewDidLoad()

      taskTitle.text = selectedTask
      taskDetail.text = taskDetails

      taskDetail.textColor = UIColor.lightGray
      navigationItem.largeTitleDisplayMode = .never
    }

  func textViewDidBeginEditing(_ textView: UITextView) {
    if taskDetail.textColor == UIColor.lightGray {
      taskDetail.text = nil
      taskDetail.textColor = UIColor.black
    }
  }

  func textViewDidEndEditing(_ textView: UITextView) {
    if taskDetail.text.isEmpty {
      taskDetail.text = "Details..."
      taskDetail.textColor = UIColor.lightGray
    }
  }

  override func viewWillAppear(_ animated: Bool) {
    taskTitle.becomeFirstResponder()
  }


  @IBAction func doneButtonPressed(_ sender: UIBarButtonItem) {
    let newTask = Task(context: self.context)
    newTask.title = taskTitle.text!
    newTask.details = taskDetail.text!
    newTask.parentCategory = taskCategory!

    delegate?.detailViewController(self, didFinishAdding: newTask)

    // self.taskArray.append(newTask)
    self.saveTasks()

    navigationController?.popViewController(animated: true)

  }


  func saveTasks() {

    do {
      try context.save()
    } catch {
      print("Error saving context \(error)")
    }
  }

}

Here is the code from the List View controller, which should display the new item as soon as it is created:

import UIKit
import CoreData

class TaskListTableViewController: UITableViewController, DetailViewControllerDelegate  {

    var tasks = [Task]()
    var selectedCategory: Category? {
        didSet {
            loadTasks()
        }
    }
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext



    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.largeTitleDisplayMode = .never

        title = selectedCategory?.name
        loadTasks()
        tableView.reloadData()

        // self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

  func detailViewController(_ controller: DetailViewController, didFinishAdding task: Task) {

    let newRowIndex = tasks.count
    tasks.append(task)
    let indexPath = IndexPath(row: newRowIndex, section: 0)
    let indexPaths = [indexPath]
    tableView.insertRows(at: indexPaths, with: .automatic)
    tableView.reloadData()

    navigationController?.popViewController(animated: true)
  }


  // TODO: finish this
  func detailViewController(_ controller: DetailViewController, didFinishEditing task: Task) {

  }


    // MARK: - Table view data source

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


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)

        let task = tasks[indexPath.row]
        let label = cell.viewWithTag(1001) as! UILabel
        label.text = task.title

        return cell
    }


    // MARK: - Navigation

  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "AddItem" {
      let destinationVC = segue.destination as! DetailViewController
      destinationVC.taskCategory = selectedCategory
    } else if segue.identifier == "EditItem" {
      let destinationVC = segue.destination as! DetailViewController
      destinationVC.taskCategory = selectedCategory
      let indexPath = tableView.indexPathForSelectedRow!
      let task = tasks[indexPath.row]
      destinationVC.selectedTask = task.title
      destinationVC.taskDetails = task.details

    }
  }


  func loadTasks(with request: NSFetchRequest<Task> = Task.fetchRequest(), predicate: NSPredicate? = nil) {

    let categoryPredicate = NSPredicate(format: "parentCategory.name MATCHES %@", selectedCategory!.name!)

    request.predicate = categoryPredicate

    do {
      tasks = try context.fetch(request)
    } catch {
      print("Error fetching data \(error)")
    }

    tableView.reloadData()
  }

  @IBAction func addTaskButton(_ sender: UIBarButtonItem) {
    print("new task added")
  }

}

Upvotes: 0

Views: 56

Answers (1)

Shehata Gamal
Shehata Gamal

Reputation: 100533

You need to set the delegate in prepareForSegue

destinationVC.delegate = self

Upvotes: 1

Related Questions