How to get variable in TableViewCell from TableView?

Hello,

I'm having a little trouble with a simple list making app I'm developing. I have two lists- a parent list and a child list- and when the user taps on a button in a parent list tableViewCell, I want to pass some data to the child list to populate it. The parent list contains objects called "compartments", and each compartment contains an array of "items", which I'll use to populate the child list. I need to access the array of compartments in CompartmentTableViewController in order to get the array of child items stored in it. I'd really appreciate any help at all. Please feel free to ask for more details or more code. Thank you so much!


//
//  CompartmentTableViewController.swift
//  CompartmentsApp
//
//  Created by James Kershner on 3/30/19.
//  Copyright © 2019 James Kershner. All rights reserved.
//

import UIKit
import os.log

class CompartmentTableViewController: UITableViewController
{
    // MARK: Properties
    var compartments = [Compartment]()
    var items = [Item]()
    let date1 = Date()
    let date2 = Date()
    let date3 = Date()
    
    // MARK: Private Methods
    private func loadSampleCompartments()
    {
        // First populate a sample item list
        guard let item1 = Item.init(name: "Do the dishes", date: date1, statusColor: UIColor.blue, colorList: [UIColor.blue, UIColor.green, UIColor.yellow]) else
        {
            fatalError("Unable to instantiate item1")
        }
        guard let item2 = Item.init(name: "Feed the dogs", date: date2, statusColor: UIColor.yellow, colorList: []) else
        {
            fatalError("Unable to instantiate item2")
        }
        
        guard let item3 = Item.init(name: "Finish economics paper", date: date3, statusColor: UIColor.purple, colorList: [UIColor.orange, UIColor.green]) else
        {
            fatalError("Unable to instantiate item3")
        }
        
        items += [item1, item2, item3]
        
        // Now populate the sample Compartment list
        guard let compartment1 = Compartment(compartmentName: "Shopping List", itemList: items, compartmentColor: UIColor.blue, colorIndex: 1) else
        {
            fatalError("Unable to instantiate Compartment 1")
        }
        
        guard let compartment2 = Compartment(compartmentName: "Student List", itemList: items, compartmentColor: UIColor.purple, colorIndex: 5) else
        {
            fatalError("Unable to instantiate Compartment 2")
        }
        
        guard let compartment3 = Compartment(compartmentName: "Work To-dos", itemList: items, compartmentColor: UIColor.orange, colorIndex: 4) else
        {
            fatalError("Unable to instantiate Compartment 3")
        }
        
        compartments += [compartment1, compartment2, compartment3]
    }
    
    private func saveCompartments()
    {
        let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(compartments, toFile: Compartment.ArchiveURL.path)
        if isSuccessfulSave
        {
            os_log("Compartments saved successfully.", log: OSLog.default, type: .debug)
        }
        else
        {
            os_log("Failed to save compartments...", log: OSLog.default, type: .debug)
        }
    }
    
    private func loadCompartments() -> [Compartment]?
    {
        return NSKeyedUnarchiver.unarchiveObject(withFile: Compartment.ArchiveURL.path) as? [Compartment]
    }
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        // use the edit button provided by the table view controller.
        navigationItem.leftBarButtonItem = editButtonItem
        
        // Now load the compartments
        if let savedCompartments = loadCompartments()
        {
            compartments += savedCompartments
        }
        else
        {
            loadSampleCompartments()
        }
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int
    {
        return 1
    }

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

    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cellIdentifier = "CompartmentTableViewCell"
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? CompartmentTableViewCell else
        {
            fatalError("The dequeued cell is not an instance of MealTableViewCell.")
        }
        
        // Fetches the appropriate meal for the data source layout.
        let compartment = compartments[indexPath.row]

        // Configure the cell.
        cell.compartmentName.text = compartment.compartmentName
        cell.compartmentColor.backgroundColor = compartment.compartmentColor

        return cell
    }
    
    // MARK: Actions
    @IBAction func unwindToCompartmentsList(sender: UIStoryboardSegue)
    {
        if let sourceViewController = sender.source as? CompartmentEditViewController, let compartment = sourceViewController.compartment
        {
            if let selectedIndexPath = tableView.indexPathForSelectedRow
            {
                // Update an existing compartment
                compartments[selectedIndexPath.row] = compartment
                tableView.reloadRows(at: [selectedIndexPath], with: .none)
            }
            else
            {
                // Add a new compartment
                let newIndexPath = IndexPath(row: compartments.count, section: 0)
                compartments.append(compartment)
                tableView.insertRows(at: [newIndexPath], with: .automatic)
            }
            
            saveCompartments()
        }
    }
    

    /*
    // Override to support conditional editing of the table view.
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false 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, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
    {
        if editingStyle == .delete
        {
            // Delete the row from the data source
            compartments.remove(at: indexPath.row)
            saveCompartments()
            tableView.deleteRows(at: [indexPath], with: .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
        }    
    }
    

    /*
    // Override to support rearranging the table view.
    override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {

    }
    */

    /*
    // Override to support conditional rearranging of the table view.
    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the item to be re-orderable.
        return true
    }
    */

    
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?)
    {
        super.prepare(for: segue, sender: sender)
        
        switch(segue.identifier ?? "")
        {
        case "AddCompartment":
            os_log("Adding a new compartment", log: OSLog.default, type: .debug)
        case "showCompartmentDetail":
            guard let compartmentDetailViewController = segue.destination as? CompartmentEditViewController else
            {
                fatalError("Unexpected destination: \(segue.destination)")
            }
            guard let selectedCompartmentCell = sender as? CompartmentTableViewCell else
            {
                fatalError("Unexpected sender: \(sender)")
            }
            
            guard let indexPath = tableView.indexPath(for: selectedCompartmentCell) else
            {
                fatalError("The selected cell is not being displayed by the table")
            }
            
            let selectedCompartment = compartments[indexPath.row]
            compartmentDetailViewController.compartment = selectedCompartment
        default:
            fatalError("Unexpected Segue Identifier: \(segue.identifier)")

        }
    }
    

}

Here's the tableViewCell code:

//
//  CompartmentTableViewCell.swift
//  CompartmentsApp
//
//  Created by James Kershner on 3/30/19.
//  Copyright © 2019 James Kershner. All rights reserved.
//

import UIKit

protocol CompartmentCellDelegate: class
{
    func didSelectShowItemList(itemList: [Item]);
}

class CompartmentTableViewCell: UITableViewCell
{
    // MARK: Properties
    @IBOutlet var compartmentColor: UILabel!
    @IBOutlet var compartmentName: UILabel!
    
    weak var delegate: CompartmentCellDelegate?
    
    var indexPath: IndexPath?
    
    //var itemList: [Item]
    
    override func awakeFromNib()
    {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool)
    {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

    @IBAction func showItemList(_ sender: UIButton)
    {
        
        delegate?.didSelectShowItemList(itemList: // TROUBLE HERE)
    }
}

I cannot find any classes conforming to your `CompartmentCellDelegate`, so it is not clear enough what you really want to do.


But generally, passing something more than available should be considered to be a bad design.


Try changing your `CompartmentCellDelegate` as follows:

protocol CompartmentCellDelegate: class {
    func didSelectShowItemList(for cell: CompartmentTableViewCell)
}


And re-design other parts of your code based on this protocol.

You should define the delegate when you create cells


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cellIdentifier = "CompartmentTableViewCell"
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? CompartmentTableViewCell else
        {
            fatalError("The dequeued cell is not an instance of MealTableViewCell.")
        }
       
        // Fetches the appropriate meal for the data source layout.
        let compartment = compartments[indexPath.row]

        // Configure the cell.
        cell.compartmentName.text = compartment.compartmentName
        cell.compartmentColor.backgroundColor = compartment.compartmentColor
        cell.delegate = self

        return cell
    }

and get the parent class conform to it


class CompartmentTableViewController: UITableViewController, CompartmentCellDelegate { }


Finally, you need to implement didSelectShowItemList

Did you solve your issue ? If so, great and don't forget to close the thread.

How to get variable in TableViewCell from TableView?
 
 
Q