1

I have used blocks in cell for getting switch value but now my problem is that deinit not called where i used the blocks. it is completely working previously but in swift 3.0 it is not working.

My switch cell :

import UIKit

class CellSwitch: UITableViewCell {

    @IBOutlet weak var objSwitch: UISwitch!
    @IBOutlet weak var btnInfo: UIButton!
    @IBOutlet weak var lblTitle: UILabel!
    var blockSwitch_Change : ((_ isOn:Bool) -> Void)!
    var blockBtn_Clicked : (() -> Void)!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.lblTitle.font = Font.init(Font.FontType.custom(Font.FontName.NotoSans_Regular), size: Font.FontSize.standard(Font.StandardSize.Regular)).instance
        // Initialization code
    }
    //MARK:- switch object change
    @IBAction func switch_ValChanged(_ obj:UISwitch){
        self.blockSwitch_Change?(obj.isOn)
    }

    //MARK:-  button clicked
    @IBAction func btnInfo_Clicked(_ sender: UIButton) {
        self.blockBtn_Clicked?()
    }
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Uses of this cell

let cell = tableView.dequeueReusableCell(withIdentifier: CellSwitch.identifier) as? CellSwitch
                cell?.lblTitle.textColor = Color.custom(hexString: objModel.titleLblColor, alpha: 1.0).value
                cell?.lblTitle.text = objModel.strTitle
                cell?.objSwitch.isOn = objModel.isOn
                cell?.btnInfo.isHidden = !objModel.isInfoBtn
                cell?.blockBtn_Clicked = { 
                   print("button clicked")
                }
                cell?.blockSwitch_Change = { (isOn) in
                    print("switch value changed \(isOn)")
                }
                if objModel.isEnable == false
                {
                    cell?.isUserInteractionEnabled = false
                    cell?.contentView.alpha = 0.5
                }
                else
                {
                    cell?.isUserInteractionEnabled = true
                    cell?.contentView.alpha = 1.0
                }
                return cell!

Also if i comment this two blocks then my deinit will called.

Chirag Shah
  • 3,034
  • 1
  • 30
  • 61

1 Answers1

3

It sounds like you are creating a retain cycle by referencing the view controller strongly inside the blocks. Instead you should create a weak reference to the vc to use. This is my preferred method

cell?.blockBtn_Clicked = { [weak self]
    print("button clicked")
    self?.viewModel.//do something
}
cell?.blockSwitch_Change = { [weak self] (isOn) in
    print("switch value changed \(isOn)")
    self?.viewModel.//do something
}

The [weak self] portion will pass a weak reference of self into the block, although note this reference is now an optional. You can then use optional chaining or unwrap it after that.

Aidan Malone
  • 400
  • 3
  • 7
  • As an alternative you can also use [unowned self]. This will also create a weak reference, but it won't be an optional (It will be implicitly unwrapped before being passed into the block). If your unsure weak is typically safer as it protects from a potential crash, but its worth considering as perhaps you may not want the app to continue execution in the scenario where this block is called and the view controller has been removed from memory. – Aidan Malone Jul 10 '18 at 11:18