\$\begingroup\$i don't know if the behaviour is changed with isForHeaderCell but in non header you forget to set cell.btnReplyTappedClousre to nil - because you can also get an reused cell from header\$\endgroup\$
– mueschaAug 22 '18 at 20:31

You seem to be forwarding a lot of calls that are doing nothing except forwarding. So the only thing you really need to do is to forward the function you want to call in the end. What you need to understand is that functions can be parameters where blocks are asked and vice versa. A block is an anonymous function and if the in/out matches you can use it.

So technically you only need to pass the function that is going to do the required work all the way up and you're good. For example I have a class that fetches some data:

And this block could be passed all the way up the chain, so you call down once.

func configure(with fetchStuff: (Int) -> ())

I also don't understand why you pass the Cell itself as a parameter. Perhaps because the way the @IBAction functions are structured by default but it's better to ignore it unless you have some really pressing reason to got back to exactly that cell.

Last but not least, providing defaults is not that bad when dealing with blocks that almost surely will be set during runtime:

public var btnReplyTappedClousre:((CommentCell) -> (Void))?

Could be:

private var replyAction: (Int) -> () = { _ in
assertionFailure("This block should always be replaced by the configure function before the cell is shown")
}

Let me explain the changes in detail:

It can be private because it's set through your configure function and will only ever be called from within the cell. Better encapsulation.

It does not relate to the button but to what actually happens when you tap the button. So the @IBAction func replyButtonTapped() will call replyAction(chatId)

It only passes the required data (in this case the chat id). Nobody outside of CommentCell needs to know anything about CommentCell

The empty block containing only the assertionFailure will warn any boneheaded colleague that did not call configure during testing but will not crash when released (if it managed to escape during testing)

The block will always be set so you're not dealing with optionals anymore