Protocol Delegate возвращает nil swift - PullRequest
0 голосов
/ 06 мая 2020

Мне нужно было делегировать действие щелчка для моего UIView класса моему UIViewController классу. Поэтому я хотел, чтобы при нажатии кнопки в моем подвиде вызывалась функция в моем классе BrowserViewController.

Я использую protocol для достижения этой цели, но я обнаружил, что мой delegate возвращает nil. Я не знаю, что делаю не так. Я застрял на этом уже несколько недель.

BrowseViewController

class BrowseViewController: UIViewController {
    // Content container
    lazy var container: UIStackView = {
        let contentView = UIStackView(frame: .zero)
        contentView.axis = .vertical
        contentView.spacing = 10
        contentView.willSetConstraints()
        return contentView
    }()

    var explore: Explore! = Explore()// Explore section
    var categoryItem: CategoryItem! = CategoryItem() //Category Item

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController!.navigationBar.isHidden = true
        self.setupInterface()
    }

    // MARK: SETUP
    private func setupInterface() {
        self.embedInScrollView(content: self.container)
        self.setupSearch() // Search
        self.setupExplore() // Explore

        DispatchQueue.main.async {
            self.container.setBackground(color: UIColor.constants.lightGray)
        }
    }

    // MARK: SEARCH HEADER
    private func setupSearch() {
        self.searchHeader = SearchHeader(frame: .zero)
        self.searchHeader.willSetConstraints()

        self.container.addArrangedSubview(self.searchHeader)
        let constraints = [
            self.searchHeader.topAnchor.constraint(equalTo: self.container.topAnchor),
            self.searchHeader.heightAnchor.constraint(equalToConstant: 156),
            self.searchHeader.widthAnchor.constraint(equalTo: self.view.widthAnchor),
//            self.searchHeader.centerXAnchor.constraint(equalTo: self.container.centerXAnchor)
        ]
        NSLayoutConstraint.activate(constraints)

        DispatchQueue.main.async {
            self.searchHeader.backgroundColor = UIColor(patternImage: UIImage(named: "header_background")!.resize(to: CGSize(width: self.searchHeader.bounds.width, height: self.searchHeader.bounds.height)))
            self.searchHeader.setGradientBackground(gradientTop: UIColor.constants.darkBlue.withAlphaComponent(0.9).cgColor, gradientBottom: UIColor.constants.darkBlue.cgColor, opacity: 0.9)
            self.searchHeader.applyConstraints()
        }
    }

    // MARK: EXPLORE COMPONENT
    private func setupExplore() {
        self.categoryItem.isUserInteractionEnabled = true
        self.categoryItem.delegate = self
        self.container.addArrangedSubview(self.explore)
        self.explore.willSetConstraints()

        DispatchQueue.main.async {
            NSLayoutConstraint.activate([
                self.explore.leftAnchor.constraint(equalTo: self.view.leftAnchor),
                self.explore.rightAnchor.constraint(equalTo: self.view.rightAnchor),
                self.explore.heightAnchor.constraint(equalToConstant: 240),
            ])
            self.explore.configure()
            self.setupDailyPicks()
        }
    }

    // MARK: DAILY PICKS
    func setupDailyPicks() {
        self.dailyPicks.delegate = self
        self.container.addArrangedSubview(self.dailyPicks)
        self.dailyPicks.willSetConstraints()

        NSLayoutConstraint.activate([
            self.dailyPicks.heightAnchor.constraint(equalToConstant: 297),
            self.dailyPicks.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            self.dailyPicks.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        ])
        self.dailyPicks.load()
        self.container.setNeedsDisplay()
        self.container.setNeedsLayout()
        self.setupFreshFinds()
    }

extension BrowseViewController: ExploreDelegate {
    func categoryClicked(category: ProductCategory) {
        let categoryView = ProductByCategoryView()
        categoryView.category = category
        categoryView.modalPresentationStyle = .overCurrentContext
        self.navigationController?.pushViewController(categoryView, animated: true)
    }
}

Explore.xib

protocol ExploreDelegate:UIViewController {
       func categoryClicked(category: ProductCategory)
   }
//enum Categories: String, CaseIterable {
//
//}

class Explore: UIView {

    @IBOutlet weak var electronics: CategoryItem!
    @IBOutlet weak var mobilePhones: CategoryItem!
    @IBOutlet weak var travel: CategoryItem!
    @IBOutlet weak var womenFashion: CategoryItem!
    @IBOutlet weak var menFashion: CategoryItem!
    @IBOutlet weak var health: CategoryItem!
    @IBOutlet weak var arts: CategoryItem!
    @IBOutlet weak var babies: CategoryItem!
    @IBOutlet weak var rentals: CategoryItem!
    @IBOutlet weak var realEstate: CategoryItem!
    @IBOutlet weak var agriculture: CategoryItem!
    @IBOutlet weak var jobs: CategoryItem!
    @IBOutlet weak var everything: CategoryItem!


    var categoriesView: UIView!
    var titleLabel: UILabel!

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    func setup() {
        self.titleLabel = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 133, height: 20)))
        self.titleLabel.font = UIFont(name: "Hind", size: 18)?.bold
        self.titleLabel.text = "Explore Kusnap"
        self.titleLabel.willSetConstraints()
        self.addSubview(self.titleLabel)

        // Container for categories
        let categoriesContainer = UIScrollView()

        categoriesContainer.isScrollEnabled = true
        categoriesContainer.willSetConstraints()

        self.categoriesView = loadViewFromNib()
        self.categoriesView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: self.bounds.width, height: 186))
        self.categoriesView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        categoriesContainer.addSubview(self.categoriesView)
        self.categoriesView.willSetConstraints()
        self.addSubview(categoriesContainer)

        NSLayoutConstraint.activate([
            self.titleLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 14),
            self.titleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 14),

            categoriesContainer.heightAnchor.constraint(equalToConstant: 186),
            categoriesContainer.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -14),
            categoriesContainer.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 14),
            categoriesContainer.topAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 14),

            self.categoriesView.topAnchor.constraint(equalTo: categoriesContainer.topAnchor),
            self.categoriesView.bottomAnchor.constraint(equalTo: categoriesContainer.bottomAnchor),
            self.categoriesView.leftAnchor.constraint(equalTo: categoriesContainer.leftAnchor),
            self.categoriesView.rightAnchor.constraint(equalTo: categoriesContainer.rightAnchor),
        ])
    }

    func configure() {
        let categoryButtons = [electronics, mobilePhones, travel, womenFashion, menFashion, health, arts, babies, rentals, realEstate, agriculture, jobs, everything]
        let categories: [ProductCategory] = ProductCategory.allCases
        categoryButtons.enumerated().forEach({
            $0.element?.category = categories[$0.offset]
        })        
        self.layoutIfNeeded()
    }
}

class CategoryItem: UIView {
    weak 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) {
       print(self.delegate!) //returns nil
        self.delegate?.categoryClicked(category: ProductCategory.arts)
        self.tapped?(self.category)

    }
}

1 Ответ

1 голос
/ 07 мая 2020

вам нужно сделать делегата в классе explore .... класс explore будет связываться с вашим основным контроллером

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


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

    @objc func categoryTapped(_ sender: UIGestureRecognizer) {
       print(self.delegate!) //returns nil
        self.delegate?.categoryClicked(category: ProductCategory.arts)


    }
}
   protocol BrowseDelegate:AnyObject {
       func categoryClicked(category: ProductCategory)
   }
    protocol ExploreDelegate: AnyObject {
       func categoryClicked(category: ProductCategory)
   }
     class Explore: UIView {

            @IBOutlet weak var electronics: CategoryItem!
            @IBOutlet weak var mobilePhones: CategoryItem!
            @IBOutlet weak var travel: CategoryItem!
            @IBOutlet weak var womenFashion: CategoryItem!
            @IBOutlet weak var menFashion: CategoryItem!
            @IBOutlet weak var health: CategoryItem!
            @IBOutlet weak var arts: CategoryItem!
            @IBOutlet weak var babies: CategoryItem!
            @IBOutlet weak var rentals: CategoryItem!
            @IBOutlet weak var realEstate: CategoryItem!
            @IBOutlet weak var agriculture: CategoryItem!
            @IBOutlet weak var jobs: CategoryItem!
            @IBOutlet weak var everything: CategoryItem!

            weak var browseDelegate: BrowseDelegate!
            var categoriesView: UIView!
            var titleLabel: UILabel!

            override init(frame: CGRect) {
                super.init(frame: frame)
                self.setup()
            }

            required init?(coder aDecoder: NSCoder) {
                super.init(coder: aDecoder)
                self.setup()
            }

            func setup() {
                self.titleLabel = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 133, height: 20)))
                self.titleLabel.font = UIFont(name: "Hind", size: 18)?.bold
                self.titleLabel.text = "Explore Kusnap"
                self.titleLabel.willSetConstraints()
                self.addSubview(self.titleLabel)

                // Container for categories
                let categoriesContainer = UIScrollView()

                categoriesContainer.isScrollEnabled = true
                categoriesContainer.willSetConstraints()

                self.categoriesView = loadViewFromNib()
                self.categoriesView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: self.bounds.width, height: 186))
                self.categoriesView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

                categoriesContainer.addSubview(self.categoriesView)
                self.categoriesView.willSetConstraints()
                self.addSubview(categoriesContainer)

                NSLayoutConstraint.activate([
                    self.titleLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 14),
                    self.titleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 14),

                    categoriesContainer.heightAnchor.constraint(equalToConstant: 186),
                    categoriesContainer.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -14),
                    categoriesContainer.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 14),
                    categoriesContainer.topAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 14),

                    self.categoriesView.topAnchor.constraint(equalTo: categoriesContainer.topAnchor),
                    self.categoriesView.bottomAnchor.constraint(equalTo: categoriesContainer.bottomAnchor),
                    self.categoriesView.leftAnchor.constraint(equalTo: categoriesContainer.leftAnchor),
                    self.categoriesView.rightAnchor.constraint(equalTo: categoriesContainer.rightAnchor),
                ])
             electronics.delegate = self
             mobilePhones.delegate = self
             travel.delegate = self
             womenFashion.delegate = self
             menFashion.delegate = self
             health.delegate = self
             arts.delegate = self
             babies.delegate = self
             rentals.delegate = self
             realEstate.delegate = self
             agriculture.delegate = self
             jobs.delegate = self
             everything.delegate = self
            }

            func configure() {
                let categoryButtons = [electronics, mobilePhones, travel, womenFashion, menFashion, health, arts, babies, rentals, realEstate, agriculture, jobs, everything]
                let categories: [ProductCategory] = ProductCategory.allCases
                categoryButtons.enumerated().forEach({
                    $0.element?.category = categories[$0.offset]
                })        
                self.layoutIfNeeded()
            }
        }
    extension Explore: ExploreDelegate {
        func categoryClicked(category: ProductCategory) {
          // this function will be called ... from here you tell your BrowseViewController to perform task through delegate
       self.browseDelegate?.categoryClicked(category: ProductCategory.arts)
        }
    }

Then in your browse class 

class BrowseViewController: UIViewController {
    // Content container
    lazy var container: UIStackView = {
        let contentView = UIStackView(frame: .zero)
        contentView.axis = .vertical
        contentView.spacing = 10
        contentView.willSetConstraints()
        return contentView
    }()

    var explore: Explore! = Explore()// Explore section


    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController!.navigationBar.isHidden = true
        self.setupInterface()
    }

    // MARK: SETUP
    private func setupInterface() {
        self.embedInScrollView(content: self.container)
        self.setupSearch() // Search
        self.setupExplore() // Explore

        DispatchQueue.main.async {
            self.container.setBackground(color: UIColor.constants.lightGray)
        }
    }

    // MARK: SEARCH HEADER
    private func setupSearch() {
        self.searchHeader = SearchHeader(frame: .zero)
        self.searchHeader.willSetConstraints()

        self.container.addArrangedSubview(self.searchHeader)
        let constraints = [
            self.searchHeader.topAnchor.constraint(equalTo: self.container.topAnchor),
            self.searchHeader.heightAnchor.constraint(equalToConstant: 156),
            self.searchHeader.widthAnchor.constraint(equalTo: self.view.widthAnchor),
//            self.searchHeader.centerXAnchor.constraint(equalTo: self.container.centerXAnchor)
        ]
        NSLayoutConstraint.activate(constraints)

        DispatchQueue.main.async {
            self.searchHeader.backgroundColor = UIColor(patternImage: UIImage(named: "header_background")!.resize(to: CGSize(width: self.searchHeader.bounds.width, height: self.searchHeader.bounds.height)))
            self.searchHeader.setGradientBackground(gradientTop: UIColor.constants.darkBlue.withAlphaComponent(0.9).cgColor, gradientBottom: UIColor.constants.darkBlue.cgColor, opacity: 0.9)
            self.searchHeader.applyConstraints()
        }
    }

    // MARK: EXPLORE COMPONENT
    private func setupExplore() {

        self.container.addArrangedSubview(self.explore)
        self.explore.willSetConstraints()
        self.explore.browseDelegate = self
        DispatchQueue.main.async {
            NSLayoutConstraint.activate([
                self.explore.leftAnchor.constraint(equalTo: self.view.leftAnchor),
                self.explore.rightAnchor.constraint(equalTo: self.view.rightAnchor),
                self.explore.heightAnchor.constraint(equalToConstant: 240),
            ])
            self.explore.configure()
            self.setupDailyPicks()
        }
    }

    // MARK: DAILY PICKS
    func setupDailyPicks() {
        self.dailyPicks.delegate = self
        self.container.addArrangedSubview(self.dailyPicks)
        self.dailyPicks.willSetConstraints()

        NSLayoutConstraint.activate([
            self.dailyPicks.heightAnchor.constraint(equalToConstant: 297),
            self.dailyPicks.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            self.dailyPicks.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        ])
        self.dailyPicks.load()
        self.container.setNeedsDisplay()
        self.container.setNeedsLayout()
        self.setupFreshFinds()
    }

extension BrowseViewController: BrowseDelegate {
    func categoryClicked(category: ProductCategory) {
        let categoryView = ProductByCategoryView()
        categoryView.category = category
        categoryView.modalPresentationStyle = .overCurrentContext
        self.navigationController?.pushViewController(categoryView, animated: true)
    }
} 
...