0

I have TableView with cells and I have button on each cell. I want to add some functionality - when user presses button in cell some request is made to server and cell disappears from TableView.

How i can perform this? I know method to delete cell from tableView but to use it i need to get access to tableView from it's cell.

moonvader
  • 19,761
  • 18
  • 67
  • 116

1 Answers1

9

One way could be to add a callback closure to a custom cell and execute it upon cell selection. your view controller would hook this callback up in tableView(_,cellForIndexPath:) or tableView(_, cellWillAppear:)


import UIKit

class SelectionCallbackTableViewCell: UITableViewCell {
    var selectionCallback: (() -> Void)?
    @IBOutlet weak var button: UIButton!
    @IBAction func buttonTapped(sender: UIButton) {
        self.selectionCallback?()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        self.contentView.addSubview(self.button)
    }
}

register the cell for the tableview. I did it in the storyboard.


import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    var array = [1,1]
    override func viewDidLoad() {
        super.viewDidLoad()

        for x in stride(from: 2, through: 30, by: 1){
            let i = array[x-2]
            let j = array[x-1]
            array.append(i+j)
        }
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

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

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! SelectionCallbackTableViewCell
        cell.selectionCallback = {
            println("\(self.array[indexPath.row]) at \(indexPath.row) on \(tableView) selected")
        }
        cell.textLabel?.text = "\(self.array[indexPath.row])"
        return cell
    }

}

Now implement the callback closure as needed

cell.selectionCallback = {
    println("\(self.array[indexPath.row]) at \(indexPath.row) on \(tableView) selected")
}

will result in logs like

832040 at 29 on <UITableView: 0x7fe290844200; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fe2907878e0>; layer = <CALayer: 0x7fe290711e60>; contentOffset: {0, 697}; contentSize: {375, 1364}> selected

all possible helpful information are present:

  • indexPath
  • datasource object
  • table view
  • cell

if you want delete the cell after successfully informing your server, for a simple solution do:

cell.selectionCallback = {
    println("\(self.array[indexPath.row]) at \(indexPath.row) on \(tableView) selected")

    self.apiManager.deleteObject(obj, success: { response in
        self.array.removeAtIndex(indexPath.row)
        tableView.reloadData()
    }, failure:{ error in 
        // handle error
    })

}

Disclaimer:
Personally I don't recommend to implement datasources as UIViewController. It violates the SOLID principles. Instead datasources should reside in their own classes. For my own Projects I use an architecture I call "OFAPopulator", that allows me to create independent datasources for each section of a table or collection view. I chose to implement it inside the view controller here for brevity.


I missed the button part. edited.


Example code: https://github.com/vikingosegundo/CellSelectionCallback

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178