Advanced UITableView - Closure
Tags: swift, mobile, beginners
Published: 2023-11-06 16:10:24

**1.Create a subclass named `EmpTVCell`**
Cmd+N > Cocoa Touch Class > select UITableViewCell
![step 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yrtamc2rqfrt4ujy2hz7.png)

```swift
class EmpTVCell: UITableViewCell {
    @IBOutlet weak var labelEmpName: UILabel!
    @IBOutlet weak var labelEmpTeam: UILabel!
    
    // type function
    // you can assign a function expression to the variable
    // empty block by default. we will implement this in main class
    var transferEmployee: (() -> ()) = {}
    
    // whenever user presses the button -> call this function
    @IBAction func transferEmployee(_ sender: Any) {
        transferEmployee()
    }
}
```

_*NOTE: if you want to see the storyboard on the side, click button below +_
![editor on the right](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pag34km4sg0ft4aar4ss.png)

**2.Assign `identifier` to the prototype cell, `empCell`**
![identifier](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q0u83rnb8mbchil2v74w.png)

**3.Change class name to `EmpTVCell` we created earlier**
![empTVCell](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0om0vgyjaxvawhyze6ok.png)

**4.Connect the UITableView with datasource and delegate**
```swift
class ViewController: UIViewController {
    
    @IBOutlet weak var employeeTableView: UITableView!

    var employees: [Employee] = [
      Employee(name: "John", team: "Frontend"),
      Employee(name: "Jane", team: "Backend"),
      Employee(name: "Mike", team: "Product"),
      Employee(name: "Sarah", team: "Design"),
      Employee(name: "Tom", team: "Testing")
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        
        employeeTableView.dataSource = self
        employeeTableView.delegate = self
    }
}
```
In this step, we can create an extension and add both `UITableViewDataSource, UITableViewDelegate` in the extension  itself as below.
```swift
extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return employees.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // custom ui table view cell
        // you have to let class know that this is the custome class of ui table view cell!
        // so you have to specify custom subclass of ui table view cell
        // without type casting to EmpTVcell -> it will be treated as normal ui table view cell
        let cell = tableView.dequeueReusableCell(withIdentifier: "empCell", for: indexPath) as! EmpTVCell
        
        // now you can call labelEmpName and Team of subclass of ui table view cell = EmpTVCell because of the type casting above
        cell.labelEmpName.text = employees[indexPath.row].name
        cell.labelEmpTeam.text = employees[indexPath.row].team
        
        // now I can now provide a new block!
        // this is a button press event happened from another subclass (EmpTVCell subclass)
        // closure = implement between two classes
        cell.transferEmployee = {
            // transfer logic here
            print("Hello, \(self.employees[indexPath.row].name)")
            
            self.changeTeam(for: indexPath.row) {
                // reload table view for updating the rows again! it still won't work if we don't have completion handler
                // this will happen even before user enters an input
                // we only reload table after we have updated a team in the data source
                tableView.reloadRows(at: [indexPath], with: .automatic)
            }
        }
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 86
    }
}
```
_*NOTE: anything you do here is treated like you did to main class itself_

**5.Implement a button click handler** (transferEmployee - empty in the subclass, `EmpTVCell`)
```swift
class ViewController: UIViewController {
    ...
    func changeTeam(for index: Int, completion: @escaping (() -> Void)) {
        // create an alert = async, we need to wait till the action is completed before relaoading tabie View rows
        // @escaping is used to inform callers of a function that takes a closure
        // that the closure might be stored or otherwise outlive the scope of the receiving function.
        let alert = UIAlertController(title: "Team Transfer", message: "Select the team you want to transfer to", preferredStyle: .actionSheet)
        
        // enum Team
        for team in Team.allCases {
        // create an action
          let action = UIAlertAction(title: team.rawValue, style: .default) { _ in
            self.employees[index].team = team.rawValue // Frontend, Backend, Product...
              // add completion handler after I have updated data source
              completion()  // invoke our own completion handler -> reloadRows
          }
          
        // add it to the alert
          alert.addAction(action)
        }
        
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        
        // present this alert
        present(alert, animated: true)
    }
}
```

**Demo**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awevl2uctbw96ssxuprz.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vw4mo3m2yhklo9oftdu3.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6pfk01rddigahcobobdn.png)