如何使用委托过滤具有多个按钮的数据?

how to filter data with multiple buttons using delegate?

我使用的Delegate是在FilterVC中按下按钮时使用delegate过滤指定类别

我苦苦挣扎的是在 FilterVC 中设置按钮,以便过滤器在 HomeVC 中工作

我注意到当我在 @IBAction func acceptSelections 中使用委托时我的 FilterVC 出现了错误 Cannot convert value of type 'RoundButton?' to expected argument type 'String?' when使用委托控制类别时调用按钮

import UIKit
import Firebase
import FirebaseFirestore

class HomeViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    @IBOutlet var activeFiltersStackView: UIStackView!
    @IBOutlet var stackViewHeightConstraint: NSLayoutConstraint!
    @IBOutlet var jewelryFilterLbl: UILabel!
    @IBOutlet var hatFilterLbl: UILabel!   
    @IBOutlet var shoeFilterLbl: UILabel!
    @IBOutlet var apparelFilterLbl: UILabel!
    @IBOutlet var gearFilterLbl: UILabel!

    private lazy var baseQuery: Query = {
      return Firestore.firestore().collection("products").limit(to: 50)
    }()

    fileprivate var query: Query?

    lazy private var filters: (navigationController: UINavigationController,
                           filtersController: FilterViewController) = {
          return FilterViewController.fromStoryboard(delegate: self)
    }()

    @IBAction func didTapClearBtn(_ sender: Any){
        filters.filtersController.clearFilters()
        controller(filters.filtersController, didSelectCategory: nil, sativa: nil, indica: nil, hybrid: nil, gear: nil)
    }

    var productSetup: [ProductList] = []
    var products: ProductList?

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        tableView.delegate = self

        // arranges products by store nearest you
        fetchProducts { (products) in
            self.productSetup = products.sorted(by: { [=10=].itemName < .itemName })
            self.productListTableView.reloadData()
        }
    }

    // fetches Firebase Data
    func fetchProducts(_ completion: @escaping ([ProductList]) -> Void) {
        let productQuery = Firestore.firestore().collection("products").limit(to: 50)
        productQuery.addSnapshotListener { (snapshot, error) in
            guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
                return
            }
            completion(snapshot.documents.compactMap( {ProductList(dictionary: [=10=].data())} ))
        }
        // shows Firestore data in log (not neccessary code just used to be seen in logs)
        productQuery.getDocuments { (snapshot, error) in
            if let error = error {
                print("Oh no! Got an error! \(error.localizedDescription)")
                return
            }
            guard let snapshot = snapshot else { return }
            let allDocuments = snapshot.documents
            for productDocument in allDocuments {
                print("I have this product \(productDocument.data())")
            }
        }
    }
}

extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return productSetup.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as?
        HomeCell else { return UITableViewCell() }

        cell.configure(withProduct: productSetup[indexPath.row])

        return cell
    }

}

extension HomeViewController: FiltersViewControllerDelegate{
    func query(withCategory jewelry: String?, hat: String?, shoe: String?, gear: String?, apparel: String?) -> Query {

      if jewelry == nil && hat == nil && shoe == nil && gear == nil && apparel == nil {
          stackViewHeightConstraint.constant = 0
          activeFiltersStackView.isHidden = true
      } else {
          stackViewHeightConstraint.constant = 44
          activeFiltersStackView.isHidden = false
      }

      var filtered = baseQuery

      // Sort and Filter data

      if let jewelry = jewelry, !jewelry.isEmpty {
          filtered = filtered.whereField("category", isEqualTo: jewelry)
      }

      if let hat = hat, ! hat.isEmpty {
          filtered = filtered.whereField("category", isEqualTo: hat)
      }

      if let shoe = shoe, !shoe.isEmpty {
          filtered = filtered.whereField("category", isEqualTo: shoe)
      }

      if let gear = gear, !gear.isEmpty {
          filtered = filtered.whereField("category", isEqualTo: gear)
      }

      if let apparel = apparel, !apparel.isEmpty {
          filtered = filtered.whereField("category", isEqualTo: apparel)
      }

      return filtered
  }

  func controller(_ controller: FilterViewController,
                  didSelectCategory jewelry: String?,
                  hat: String?,
                  shoe: String?,
                  gear: String?,
                  apparel: String?) {

        if jewelry == nil && hat == nil && shoe == nil && gear == nil && apparel == nil {
            stackViewHeightConstraint.constant = 0
            activeFiltersStackView.isHidden = true
        } else {
            stackViewHeightConstraint.constant = 44
            activeFiltersStackView.isHidden = false
        }

        let filtered = query(withCategory: jewelry, hat: hat, shoe: shoe, gear: gear, apparel: apparel)

        if let jewelry = jewelry, ! jewelry.isEmpty {
            jewelryFilterLbl.text = jewelry
            jewelryFilterLbl.isHidden = false
        } else {
            jewelryFilterLbl.isHidden = true
        }

        if let hat = hat, ! hat.isEmpty {
            hatFilterLbl.text = hat
            hatFilterLbl.isHidden = false
        } else {
            hatFilterLbl.isHidden = true
        }

        if let shoe = shoe, ! shoe.isEmpty {
            shoeFilterLbl.text = shoe
            shoeFilterLbl.isHidden = false
        } else {
            shoeFilterLbl.isHidden = true
        }

        if let gear = gear, !gear.isEmpty {
            gearFilterLbl.text = gear
            gearFilterLbl.isHidden = false
        } else {
            gearFilterLbl.isHidden = true
        }

        if let apparel = apparel, ! apparel.isEmpty {
            apparelFilterLbl.text = apparel
            apparelFilterLbl.isHidden = false
        } else {
            apparelFilterLbl.isHidden = true
        }

        query = filtered
    }

}

import UIKit
import Firebase

protocol FiltersViewControllerDelegate: NSObjectProtocol {
  func controller(_ controller: FilterViewController,
                  didSelectCategory jewelry: String?,
                  hat: String?,
                  shoe: String?,
                  gear: String?,
                  apparel: String?)
}

class FilterViewController: UIViewController {

    @IBOutlet weak var jewelryBtn: RoundButton!
    @IBOutlet weak var hatBtn: RoundButton!
    @IBOutlet weak var shoeBtn: RoundButton!
    @IBOutlet weak var gearBtn: RoundButton!
    @IBOutlet weak var apparelBtn: RoundButton!

    static func fromStoryboard(delegate: FiltersViewControllerDelegate? = nil) ->
    (navigationController: UINavigationController, filtersController: FilterViewController) {
      let navController = UIStoryboard(name: "Main", bundle: nil)
          .instantiateViewController(withIdentifier: "FiltersViewController")
      as! UINavigationController
      let controller = navController.viewControllers[0] as! FilterViewController
      controller.delegate = delegate
      return (navigationController: navController, filtersController: controller)
    }

    weak var delegate: FiltersViewControllerDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    @IBAction func filterSelect(_ sender: Any) {
        if let button : UIButton = sender as? UIButton
        {
            button.isSelected = !button.isSelected

            if (button.isSelected)
            {
                button.backgroundColor = .green
            }
            else
            {
                button.backgroundColor = .gray
            }
        }
    }

    func clearFilters() {
        apparelBtn.isSelected = false
        jewelryBtn.isSelected = false
        shoeBtn.isSelected = false
        hatBtn.isSelected = false
        gearBtn.isSelected = false
    }

    @IBAction func closeFilter(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }

    @IBAction func acceptSelections(_ sender: Any) {
        delegate?.controller(self,                          //Problem integrating the buttons to get the correct category
                             didSelectCategory: jewelryBtn,
                             hat: hatBtn,
                             shoe: shoeBtn,
                             gear: gearBtn,
                             apparel: apparelBtn)
        dismiss(animated: true)
    }
}

由于过滤器功能是纯布尔值,我建议仅 return 按钮的 isSelected

protocol FiltersViewControllerDelegate: NSObjectProtocol {
  func controller(_ controller: FilterViewController,
                  didSelectCategory jewelry: Bool,
                  hat: Bool,
                  shoe: Bool,
                  gear: Bool,
                  apparel: Bool)
}

并称之为

@IBAction func acceptSelections(_ sender: Any) {
    delegate?.controller(self,
                         didSelectCategory: jewelryBtn.isSelected,
                         hat: hatBtn.isSelected,
                         shoe: shoeBtn.isSelected,
                         gear: gearBtn.isSelected,
                         apparel: apparelBtn.isSelected)
    dismiss(animated: true)
}

好像是多选题,所以你要组合查询中的选项。