0

I have two delegates that one of them expand or collapse a cell in my tableview and one of them must print something in tableViewCell class for test. My code is as below:

protocol ExpandableHeaderViewDelegate {
func toggleSection(header: ExpandableHeaderView, section: Int)
}

protocol MenuCellDelegate {
func menuCellDidChange()
}

class ExpandableHeaderView: UITableViewHeaderFooterView {
var delegate: ExpandableHeaderViewDelegate?
var delegate2 : MenuCellDelegate?

var section: Int!

override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action:     #selector(selectHeaderAction)))
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

@objc func selectHeaderAction(gestureRecognizer: UITapGestureRecognizer)          {
let cell = gestureRecognizer.view as! ExpandableHeaderView
delegate2?.menuCellDidChange()
delegate?.toggleSection(header: self, section: cell.section)
}

func setDelegate2(delegate2: MenuCellDelegate)  {
self.delegate2 = delegate2
}
func customInit(title: String, section: Int, delegate:     ExpandableHeaderViewDelegate,width : Int,height: Int) {
    let cell = Bundle.main.loadNibNamed("MenuTableViewCell", owner: self, options: nil)?.first as! MenuTableViewCell
    let menucell = DataService.instance.getMenuCells()[section]
    if (section==3){
        cell.updateViewsWithFont(menuCell: menucell)
    }else{
        cell.updateViews(menuCell: menucell)
    }
    self.addSubview(cell)
    cell.frame.size.width = CGFloat(width)
    cell.frame.size.height = CGFloat(height / 8)

    self.section = section

self.delegate = delegate
}

override func layoutSubviews() {
super.layoutSubviews()
}

}

and my tableViewCell:

class MenuTableViewCell: UITableViewCell,MenuCellDelegate {


@IBOutlet weak var menuCellIcon: UIImageView?
@IBOutlet weak var menuCellLabel: UILabel?
@IBOutlet weak var fontAwsomeLabel: SwiftIconLabel?

let delegateTest = ExpandableHeaderView()

func updateViews(menuCell:MenuCell)  {
delegateTest.setDelegate2(delegate2: self)
menuCellIcon?.image = UIImage(named: menuCell.menuCellIcon)
menuCellLabel?.text = menuCell.menuCellLabel
}

func menuCellDidChange() {
fontAwsomeLabel?.font = UIFont.icon(from: .FontAwesome, ofSize: 30.0)
fontAwsomeLabel?.text = String.fontAwesomeIcon("angledown")
print("yyyy")
}


func updateViewsWithFont(menuCell:MenuCell) {
menuCellIcon?.image = UIImage(named: menuCell.menuCellIcon)
menuCellLabel?.text = menuCell.menuCellLabel
fontAwsomeLabel?.font = UIFont.icon(from: .FontAwesome, ofSize: 30.0)
fontAwsomeLabel?.text = String.fontAwesomeIcon("angleleft")

}

}

and my viewController:

class HomeVC:    UIViewController,UITableViewDelegate,UITableViewDataSource,ExpandableHeaderVi    ewDelegate,MenuCellDelegate {
func menuCellDidChange() {
print("eeeeeeeeee")
}




@IBOutlet weak var homeMenuTableView: UITableView!

var sections = [
MenuCell(menuCellIcon: "ico_news.png",menuCellLabel:"اطلاع رسانی",     menuSubCells: [], expanded: false),
MenuCell(menuCellIcon:"ico_filter.png",menuCellLabel:"دروازه بانی",menuSubCells: [], expanded: false),
MenuCell(menuCellIcon:"ico_sharing.png",menuCellLabel:"اشتراک گذاری خبر",menuSubCells: [], expanded: false),
MenuCell(menuCellIcon:"ico_massaging.png",menuCellLabel:"آرشیو پیام ها",
         menuSubCells:     [MenuCell(menuCellIcon:"ico_inbox.png",menuCellLabel:"آرشیو پیام",     menuSubCells: [], expanded: false),
                            MenuCell(menuCellIcon:"ico_compose.png",menuCellLabel:"پیام جدید", menuSubCells: [], expanded: false)], expanded: false),
MenuCell(menuCellIcon:"ico_massaging.png",menuCellLabel:"تنظیمات",menuSubCells: [], expanded: false)
]


override func viewDidLoad() {
super.viewDidLoad()
        self.homeMenuTableView.backgroundColor = UIColor(red: 0.0196,     green: 0.1059, blue: 0.1647, alpha: 1.0)
        let px = 1 / UIScreen.main.scale
        let frame = CGRect(x:0,y:0,width:     self.homeMenuTableView.frame.size.width,height: px)
        let line = UIView(frame: frame)
        self.homeMenuTableView.tableHeaderView = line
        line.backgroundColor = self.homeMenuTableView.separatorColor
        homeMenuTableView.tableFooterView = UIView()
        homeMenuTableView.dataSource=self
        homeMenuTableView.delegate=self
}

func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].menuSubCells.count
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return homeMenuTableView.frame.size.height / 8
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (sections[indexPath.section].expanded) {
    return homeMenuTableView.frame.size.height / 8
}
return 0
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 2
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = ExpandableHeaderView()
header.setDelegate2(delegate2: self)
header.customInit(title: sections[section].menuCellLabel, section:  section, delegate: self,width : Int(homeMenuTableView.frame.width),height :  Int(homeMenuTableView.frame.size.height))
return header
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("MenuTableViewCell", owner: self,  options: nil)?.first as! MenuTableViewCell
let menucell = sections[indexPath.section].menuSubCells[indexPath.row]
cell.updateViews(menuCell: menucell)
return cell
}

func toggleSection(header: ExpandableHeaderView, section: Int) {
sections[section].expanded = !sections[section].expanded
homeMenuTableView.beginUpdates()
for i in 0 ..< sections[section].menuSubCells.count {
    homeMenuTableView.reloadRows(at: [IndexPath(row: i, section: section)], with: .automatic)
}
homeMenuTableView.endUpdates()
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor(red: 0.0196, green: 0.1059, blue: 0.1647, alpha: 1.0)
}


}

the problem is that menuCellDidChange in viewController works fine but menuCellDidChange in MenuTableViewCell doesnt work.

moh.mehrabi
  • 43
  • 1
  • 1
  • 12
  • check this out: https://stackoverflow.com/questions/39585638/get-indexpath-of-uitableviewcell-on-click-of-button-from-cell/39585749#39585749 – Bista Nov 22 '17 at 06:01

2 Answers2

1

There are issues in your code. These two are somewhat related to the problem you are facing:

  1. You are not using weak pointers for delegates. This will result in memory leaks.

  2. In MenuTableViewCell, you are creating a new instance of ExpandableHeaderView, here, let delegateTest = ExpandableHeaderView(). How is this new instance of header view which is no way attached to the view, can call the delegate on the tap gesture action?

In my view, you need to learn how to use delegates, about weak and strong pointers, and about view hierarchy. There are tons of source material available on net. After going through these basic concepts, you would see why your code is not working.

Puneet Sharma
  • 9,369
  • 1
  • 27
  • 33
  • tank you for reply.i just added class for protocols and weak for delegates.i know that i must reference ExpandableHeaderView in tableviewcell but cause of im new in swift im learning more than just coding.so can you help me for part 2 of your answer?how i reference ExpandableHeaderView in tableviewcell. – moh.mehrabi Nov 22 '17 at 06:13
  • @moh.mehrabi: the issues are not related to Swift, but the basic understanding of iOS UIKit and delegate design pattern. Mutiple objects of MenuTableViewCell can be present, which one do you want to know, when header view has been tapped? If you want all of them to know about it, I guess, in your present setup, ViewController should be the one to tell them. – Puneet Sharma Nov 22 '17 at 06:23
  • i now understand what you were going to tell me.your answer was write.i should call delegate from homevc without creating a new instance of headerview.just fine and worked. – moh.mehrabi Nov 22 '17 at 06:59
0

When you are writing let delegateTest = ExpandableHeaderView() your creating new instance of ExpandableHeaderView() for each cell. So delegate will get called but not on a instance where you are expecting it to be called.

Instead of that you should create a variable in cell as

_weak var delegateTest: ExpandableHeaderView?

And in cellForRowAtIndexPath assign value to delegate variable like given below

cell.delegateTest = self
Martin
  • 846
  • 1
  • 9
  • 23