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

Posted

技术标签:

【中文标题】如何使用委托过滤具有多个按钮的数据?【英文标题】:how to filter data with multiple buttons using delegate? 【发布时间】:2020-01-09 13:50:41 【问题描述】:

我正在使用的Delegate用于在FilterVC中按下按钮时使用委托过滤掉指定的类别

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

我注意到,当我在 @IBAction func acceptSelections 中使用委托时,我的 FilterVC 可能出现问题,我收到错误无法转换类型“RoundButton?”的值到预期的参数类型“字符串?”当使用delegate控制哪个类别时调用按钮时

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:  $0.itemName < $1.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: $0.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)
    

【问题讨论】:

您将方法签名定义为期望可选字符串,但您正在传递按钮对象 建议:少用“控制器”这个词有助于提高可读性。 圣地亚哥小姐,为什么要将整个视图控制器(FilterViewController)发送给 HomeViewController?没有意义。 【参考方案1】:

由于过滤器功能是纯布尔值,我建议只返回按钮的 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)

这似乎是一个多项选择,因此您必须在查询中组合选项。

【讨论】:

它可以工作,但现在我在我的extension HomeViewController: FiltersViewControllerDelegate 中遇到各种错误,同样的错误是条件绑定的初始化程序必须具有可选类型,而不是“布尔”,我在每一个if 语句 当然可以,类型已更改,所有值都是非可选的,因此您可以摆脱可选绑定。你必须调整方法。

以上是关于如何使用委托过滤具有多个按钮的数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何在具有 Ajax 的单个表单中使用多个提交按钮 [关闭]

如何在 octobercms 中过滤具有多个类别的博客文章?

c#如何使用委托 触发另一个窗体的按钮刷新另一窗体

如何使用 jQuery 和 CSS 过滤具有多个值的列表?

如何使用 isotope.js 制作具有多个 slectbox 的搜索过滤器?

如何在 C# 中使用 委托