Search code examples
iosswiftclassuitableviewswift-extensions

How do I use extensions to extend an object's tableview's functionality from the calling class?


Overview
I'm trying to better understand how extensions work.
In my app I have a ViewController. There I put a view of another class. In this custom class I put a bunch of buttons and a table view. I want them to display some text inside of my tableView whenever I press them.
The problem is that I want to edit some of the table view functions in order to better adjust it to my ViewController.

What I know
All I know is based on the apple documentation

What I'm doing
What I'm trying to do, I should say, is to add functionality to a custom view's function after adding an object which is of the type of my custom class to the ViewController.

This is my custom class:

class CustomClass: UIView{
@IBOutlet weak var abtn: UIButton!
@IBOutlet weak var table: UITableView!

 func setupTable(){ 
 table.delegate = self
        table.dataSource = self
        
        table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
        table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
        
        return cell
    }
 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
      print("I want to add stuff here too")
        
    }
    //And more stuff that is not useful rn
}

Inside of the ViewController class I have declared a variable of type CustomClass.

@IBOutlet weak var custom: CustomClass!
In my viewDidLoad I call :
custom.setupTable()

What I need to do is creating an extension to edit the tableview that belongs to custom (the variable of type CustomClass that is inside of my ViewController).

I have no clue on how to do that.

I know how to work with extension to expand my code's functionality but I don't know how to use them to edit these other functions.

Question
How do I edit the tableview functions that belong to custom?
Ie. how would I be able to change the number of rows or to change the cell's layout from the class I call the object in?

I hope I was clear enough...


Solution

  • For this specific example...

    Add a property to your CustomClass:

    class CustomClass: UIView {
        
        // this may be changed by the "calling class"
        var numRows: Int = 10
        
        @IBOutlet weak var abtn: UIButton!
        @IBOutlet weak var table: UITableView!
        
        func setupTable(){
            table.delegate = self
            table.dataSource = self
            
            table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
            table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
        }
    }
    

    In your extension, use that property:

    extension CustomClass: UITableViewDelegate, UITableViewDataSource{
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            // don't make this a hard-coded number
            //return 10
            return numRows
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
            
            return cell
        }
        //And more stuff that is not useful rn
    }
    

    Then, in your "calling class", you can change that property:

    class ExampleViewController: UIViewController {
        
        let myView = CustomClass()
        
        override func viewDidLoad() {
            super.viewDidLoad()
        
            view.addSubview(myView)
            // constraints, etc
            
            // change the number of rows in the table in myView
            myView.numRows = 20
        }
        
    }
    

    More likely, though, you would be doing something like setting / changing the data for the table in your custom class.

    Here's an example, along with showing how to use a closure to "call back" to the calling class / controller:

    class CustomClass: UIView {
        
        // this may be changed by the "calling class"
        var theData: [String] = []
        
        // closure to "call back" to the controller
        var callback: ((IndexPath) -> ())?
        
        @IBOutlet weak var abtn: UIButton!
        @IBOutlet weak var table: UITableView!
        
        func setupTable(){
            table.delegate = self
            table.dataSource = self
            
            table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
            table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
        }
    }
    extension CustomClass: UITableViewDelegate, UITableViewDataSource{
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return theData.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
            cell.textLabel?.text = theData[indexPath.row]
            return cell
        }
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            // tell the controller the cell was selected
            callback?(indexPath)
        }
    }
    
    class ExampleViewController: UIViewController {
        
        let myView = CustomClass()
        
        override func viewDidLoad() {
            super.viewDidLoad()
        
            view.addSubview(myView)
            // constraints, etc
            
            // set the data in CustomClass
            myView.theData = [
                "First row",
                "Second row",
                "Third",
                "Fourth",
                "etc..."
            ]
            
            myView.callback = { indexPath in
                print("CustomClass myView told me \(indexPath) was selected!")
                // do what you want
            }
        }
        
    }