joker449
joker449

Reputation: 109

Removing items from array in custom tableViewCell

I have a custom tableviewHeaderFooterView where I set up a target event for the button in the custom tableViewCell class (checkButton is the button and its background image changes to a checkmark when a user clicks on it).

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let userModel = Data.userModels[section]
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellId") as! SectionHeader

    cell.setup(model: userModel)
    cell.checkButton.tag = section
    cell.checkButton.addTarget(self, action: #selector(handleTap), for: .touchUpInside) 

    return cell.contentView
}

And in that function I want to create or remove items from an array depending on whether the user taps on a cell or not (i.e. if they tap on the button, then add something to the array, but if they tap on that button again, then remove that object from the array.)

@objc func handleTap(sender: UIButton) {
    sender.isSelected = !sender.isSelected

    if sender.isSelected == true {
        let model = ItemModel(itemName: item, price: price)
        ItemModelFunctions.createItem(for: sender.tag, using: model)
    }
    if sender.isSelected == false {
        ItemModelFunctions.removeFromUser(from: sender.tag)
    }
    print(sender.tag)
}

Here are the createItem and removeFromUser functions:

  struct ItemModelFunctions {
    static func createItem(for userIndex: Int, using itemModel: ItemModel) {
        Data.userModels[userIndex].itemModels.append(itemModel)

    }
    static func removeFromUser(from userIndex: Int) {
        Data.itemModels.remove(at: userIndex)
    }
}

When I tap on the button twice to remove it from the array, I get an error saying Data.itemModels.remove(at: userIndex) is out of range.

I know using a prototype cell for a tableViewHeaderFooterView isn't exactly the correct way, but I've seen other programmers and YouTubers do this with success. Are my issues coming from using a prototype cell? Or am I removing the item from the array in the wrong way? Thank you all for your help!

Upvotes: 0

Views: 74

Answers (3)

Kiran K
Kiran K

Reputation: 949

   // Please maintain one more array i.e selectedIndexArray and follow below code.

     var  selectedIndexArray  = [Integer]()

        @IBAction func buttonTapped(_ sender: UIButton) {

            let button = sender
            if selectedIndexArray.contains(button.tag) {
                button.tag --> Remove this tag from  selectedIndexArray
                let model = ItemModel(itemName: item, price: price)
                ItemModelFunctions.createItem(for: sender.tag, using: model)
            } else
            {
                selectedIndexArray.append(button.tag)
                ItemModelFunctions.removeFromUser(from: sender.tag)
            }
            //reload tableview.
self.tableView.reloadData()
        }

Upvotes: 2

rs7
rs7

Reputation: 1630

Thanh Vu's solution works. Another solution would be to add an IBAction to your ViewController:

@IBAction func buttonTapped(_ sender: UIButton) {
    sender.isSelected = !sender.isSelected
    let cell = sender.superview?.superview as! SectionHeader
    if let indexPath = mainTableView.indexPath(for: cell) {
        // if sender.isSelected etc...
    }
}

Upvotes: 1

Thanh Vu
Thanh Vu

Reputation: 1739

The checkButton.addTarget function will run each time your section header is reused. Then it will duplicate event for cell when reuse many times. I think you should not use this solution. Instead of that, I think you should write delegate way to solve your problem. Ex:

protocol SectionHeaderDelegate: class {
    func checkButtonDidTap(section: SectionHeader)
}

class SectionHeader: UITableViewCell {
    weak var delegate: SectionHeaderDelegate
    @IBOutlet weak var checkButton: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()

        checkButton.addTarget(self, action: #selector(handleTap), for: .touchUpInside) 
    }

    func handleTap() {
        self.delegate.checkButtonDidTap(section: self)
    }
}

and you set cell.delegate = self in viewForHeaderInSection function. And implement protocol SectionHeaderDelegate.

Upvotes: 1

Related Questions