Chapter 2 - Checklist list

Hi, I hope you can help me. I’m sharing my two classes and a screenshot showing the ‘Add a new list’ screen as well as the storyboard highlighting the static table. Why can’t I see the table with the textField? What did I miss?

//
//  ListDetailTableViewController.swift
//  Checklists
//
//

import UIKit

/// es AnyObject por que no sé cómo se llamará el delgate que haga conform a esta clase, en este caso será AllListsViewController
protocol ListDetailViewControllerDelegate : AnyObject {
    
    /// método para tapped en Cancel button
    func listDetailViewControllerDidCancel(_ controller : ListDetailViewController)
    
    /// método para terminar de agregar una nueva lista
    func listDetailViewController(_ controller : ListDetailViewController, didFinishAdding checklist : Checklist)
    
    /// método para terminar de editar nueva lista
    func listDetailViewController(_ controller : ListDetailViewController, didFinishEditing checklist : Checklist)
    
}

class ListDetailViewController: UITableViewController, UITextFieldDelegate {
    
    @IBOutlet var textField : UITextField!
    @IBOutlet var doneBarButton : UIBarButtonItem!
    
    weak var delegate : ListDetailViewControllerDelegate?
    
    /// name of the list (Checklist) that contents ChecklistItems
    var checklistToEdit : Checklist!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        if let checklist = checklistToEdit {
            /// checklistToEdit has value in it
            
            self.title = "Edit Checklist"
            textField.text = checklist.name
            doneBarButton.isEnabled = true
            
        }
        
    }
    
    override func viewWillAppear(_ animated : Bool) {
        super.viewWillAppear(animated)
        
        /// method to pop up the keyword
        textField.becomeFirstResponder()
    }

    //MARK: - Actions
    @IBAction func close() {
        delegate?.listDetailViewControllerDidCancel(self)
    }
    
    @IBAction func done() {
        
        if let checklist = checklistToEdit {
            
            /// edition
            checklist.name = textField.text!
            delegate?.listDetailViewController(self, didFinishEditing: checklist)
            
        } else {
            
            /// añadir
            let checklist : Checklist = Checklist(name : textField.text!)
            delegate?.listDetailViewController(self, didFinishAdding: checklist)
            
        }
    }
    
    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 0
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 0
    }
    
    // MARK: - Table view Delegates
    /// the user cannot select the table cell with the text field
    override func tableView(_ tableView : UITableView, willSelectRowAt indexPath : IndexPath) -> IndexPath? {
        /// como es static cell y tenemos un textfield, regresando nil el usuario no puede seleccionar a la celda
        return nil
    }
    
    // MARK: - Text field delegates
    func textField(_ textField : UITextField, shouldChangeCharactersIn range : NSRange, replacementString string : String) -> Bool {
        
        let oldText = textField.text!
        let stringRange = Range(range, in : oldText)!
        let newText = oldText.replacingCharacters(in : stringRange, with : string)
        doneBarButton.isEnabled = !newText.isEmpty
        return true
    }

    func textFieldShouldClear(_ textField : UITextField) -> Bool {
        doneBarButton.isEnabled = false
        return true
    }
    
}

//
//  AllListsTableViewController.swift
//  Checklists
//
//

import UIKit

class AllListsTableViewController: UITableViewController, ListDetailViewControllerDelegate {
        
    /// se agregan los métodos del tableview data source y los delegates si son necesarios
    /// property
    let cellIdentifier = "ChecklistCell"
    
    /// array de Chelist
    var lists = [Checklist]()
    // var lists = Array<Checklist>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.title = "Checklists"

        /// hardcode de data model
        var list = Checklist(name : "Trabajo")
        lists.append(list)
        list = Checklist(name : "Personal")
        lists.append(list)
        list = Checklist(name : "Otros")
        lists.append(list)
        list = Checklist(name : "Compartidos")
        lists.append(list)
        
        /// register the cellIdentifier for this kind of UITabkeViewCell
        tableView.register(UITableViewCell.self, forCellReuseIdentifier : cellIdentifier)
        
        /// Enable large titles
        self.navigationController?.navigationBar.prefersLargeTitles = true
    }
    
    //MARK: - TableView datasource
    override func tableView(_ tableView : UITableView, numberOfRowsInSection section : Int) -> Int {
        
        return lists.count;
        
    }
    
    override func tableView(_ tableView : UITableView, cellForRowAt indexPath : IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier : cellIdentifier, for : indexPath)
        
        /// update cell information
        let checklist = lists[indexPath.row]
        cell.textLabel!.text = checklist.name   //textLabel es un Optional, podría contener nil
        cell.accessoryType = UITableViewCell.AccessoryType.detailDisclosureButton
        
        /// this works when you added a UILabel and edited his tag property
        /*let label = cell.viewWithTag(1000) as! UILabel
        label.text = "Hello!"
        */
        return cell
    }
    
    override func tableView(_ tableView : UITableView,
                            commit editingStyle : UITableViewCell.EditingStyle,
                            forRowAt indexPath : IndexPath) 
    {
        
        lists.remove(at: indexPath.row)
        
        let indexPaths = [indexPath]
        tableView.deleteRows(at: indexPaths, with: UITableView.RowAnimation.automatic)
    }
    
    //MARK: - TableView delegates
    override func tableView(_ tableView : UITableView, didSelectRowAt indexPath : IndexPath) {
        let checklist = lists[indexPath.row]
        
        // se manda el checklist para que el ChecklistVC coloque el nombre como titulo
        performSegue(withIdentifier : "ShowChecklist", sender : checklist)
    }
    
    
    
    //MARK: - ProtocolDelegate methods from checkLists
    
    func listDetailViewControllerDidCancel(_ controller : ListDetailViewController) {
        navigationController?.popViewController(animated : true)
    }
    
    func listDetailViewController(_ controller : ListDetailViewController, 
                                  didFinishAdding checklist : Checklist) {
        
        /// update the data model
        let newRowIndex = lists.count
        lists.append(checklist)
        
        let indexPath = IndexPath(row : newRowIndex, section : 0)
        let indexPaths = [indexPath]
        tableView.insertRows(at: indexPaths, with: UITableView.RowAnimation.automatic)
        
        navigationController?.popViewController(animated : true)
    }
    
    func listDetailViewController(_ controller : ListDetailViewController, 
                                  didFinishEditing checklist : Checklist) {
        
        if let index = lists.firstIndex(of: checklist) {
            
            let indexPath = IndexPath(row : index, section : 0)
            if let cell = tableView.cellForRow(at : indexPath) {
                
                cell.textLabel!.text = checklist.name
                
            }
            
        }
        navigationController?.popViewController(animated : true)
        
    }
 
    //MARK: - Segues programatically - Navigation
    override func prepare(for segue : UIStoryboardSegue, sender : Any?) {
        
        if segue.identifier == "ShowChecklist" {
            let controller = segue.destination as! ChecklistViewController
            controller.checklist = sender as? Checklist
            
        } else if(segue.identifier == "AddChecklist") {
            let controller = segue.destination as! ListDetailViewController
            controller.delegate = self
        }
    }
}

Hi, sorry to hear that you’re running into trouble. But while you mentioned that you can’t see the table with the text field, I’m not quite clear when you can’t see it :slightly_smiling_face:

Are you unable to see the table with the text field when you run the app? And if so, how far can you get?

Also, zipping up the project and providing a ZIP file of the whole Xcode project makes it easier to test and see what you might be seeing :slightly_smiling_face:

sure, I attached the .zip You could see the problem when tapped on the Add button at AllList…
Checklists 2.zip (93.0 KB)
I really appreciate the help! :smiley:

I believe the issue is that you left the boilerplate code for table view data source and table view delegate in place :slightly_smiling_face: If I’m not mistaken, the book tells you to remove this code …

If you have that code in place, your static tableview cell gets replaced by nil as per the code at line 94 …

2 Likes

:man_facepalming: geeez :frowning: you are right… thank you! I guess I never forget to do that when I am dealing with static cells.

1 Like