0

I needed to delegate a click action for my UIView class to my UIViewController class since Swift does not support multiple class inheritance. So i wanted it such that once a button is clicked on my subview, a function in my BrowserViewController class is called.

I am using a protocol to achieve this, but on the function does not triggered when the button is tapped. Please help me out.

View Controller


class BrowseViewController: UIViewController {

  var categoryItem: CategoryItem! = CategoryItem() //Category Item

  private func setupExplore() {
    //assign delegate of category item to controller
    self.categoryItem.delegate = self
  }
}

// delegate function to be called
extension BrowseViewController: ExploreDelegate {
  func categoryClicked(category: ProductCategory) {
    print("clicked")
    let categoryView = ProductByCategoryView()
    categoryView.category = category
    categoryView.modalPresentationStyle = .overCurrentContext

    self.navigationController?.pushViewController(categoryView, animated: true)
  }
}

Explore.swift (subview)

import UIKit

protocol ExploreDelegate: UIViewController {
  func categoryClicked(category: ProductCategory)
}

class Explore: UIView {
  var delegate: ExploreDelegate?

  class CategoryItem: UIView {
    var delegate: ExploreDelegate?
    var category: ProductCategory? {
      didSet {
        self.configure()
      }
    }

    var tapped: ((_ category: ProductCategory?) -> Void)?

    func configure() {
      self.layer.cornerRadius = 6
      self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.categoryTapped)))
      self.layoutIfNeeded()
    }

    @objc func categoryTapped(_ sender: UIGestureRecognizer) {
      delegate?.categoryClicked(category: ProductCategory.everything)
      self.tapped?(self.category)
    }
  }
}
Leejay Schmidt
  • 1,193
  • 1
  • 15
  • 24
custom apps
  • 413
  • 1
  • 8
  • 19

3 Answers3

1

Simply add a print statement inside categoryTapped.

You will then know if it is actually being tapped.

A million things could go wrong, for example, you may have forget to set the UIView to allow intertaction.

After checking that. Next add another print statement inside categoryTapped which shows you whether or not the delegate variable is null.

You'll quickly discover the problem using simple print statements.

print("I got to here!")

It's that easy.

And what about

if delegate == nil { print("it is nil!! oh no!" }
else { print("phew. it is NOT nil.") }

Debugging is really that easy at this level.

Next add a print statement inside setupExplore()

func setupExplore() {
  print("setup explore was called")
  ....

See what happens.

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • my button tap event works well as i have tested with print statements. The problem is that the delegate method don't get called. – custom apps May 05 '20 at 16:36
  • hi @customapps - add a print statement which **prints the delegate variable** - you'll see if it is there or not. it's very likely nil. – Fattie May 05 '20 at 22:51
  • do you mean like: **print(self.delegate!)** – custom apps May 06 '20 at 16:17
  • hi @customapps - sure, simply print("try this! " + delegate) will work, no need for the self. – Fattie May 06 '20 at 18:52
  • what about something like " if delegate == nil { print("it is nil!! oh no!" } else { print("phew. it is NOT nil.") } – Fattie May 06 '20 at 18:52
  • delegate returns nil. what could be wrong with my delegate? – custom apps May 07 '20 at 14:50
  • hi @customapps , as a new user U need to add upvotes to helpful answers. Also edit your code now pleaae to show ALL the print statements you have added. Finally please note the new addition to my answer and try that. Good luck – Fattie May 07 '20 at 17:22
0

I don't see any piece of code which sets the delegate.

First of all, define delegate as a property inside CategoryItem class, Then you must set the current instance of BrowseViewController to the delegate variable of CategoryItem. Now you can expect your method being called.

Mahsa Yousefi
  • 206
  • 1
  • 7
  • please review my code. i have effected the changes but same result – custom apps May 05 '20 at 16:16
  • First, define `delegate` property as week to avoid memory leakage problem `weak var delegate: ExploreDelegate `. Then try to print out delegate inside funtion `@objc func categoryTapped(_ sender: UIGestureRecognizer)` to determine delegate has value or not. – Mahsa Yousefi May 06 '20 at 04:13
  • i did so. it returns null – custom apps May 07 '20 at 14:41
0

There are a few things that could cause the delegate method to not be triggered in this code:

  1. Ensure that isUserInteractionEnabled = true on your CategoryItem. This is probably best done in either the configure() function in the CategoryItem or in the setupExplore() function of the BrowseViewController.
  2. Make sure that the setupExplore() function on the BrowseViewController is being called, and that the category is being set on the CategoryItem to trigger the configure function. Otherwise, either the delegate or the gesture recognizer might not being set.

Side Note - weak vs strong delegate

On a side note, it is usually best practice to make your delegate properties weak var rather that having them be a strong reference, as this makes them prone to strong retain cycles.

Therefore, you might want to consider making the var delegate: ExploreDelegate? on your CategoryItem into weak var delegate: ExploreDelegate?. For more information on this problem, view this post.

Leejay Schmidt
  • 1,193
  • 1
  • 15
  • 24