当前位置: 首页 > 面试题库 >

如何在同一视图中将多个选择器视图与不同的数据源一起使用?

廖弘伟
2023-03-14
问题内容

我有一个视图,其中有三个选择器视图。两个选择器视图具有相同的数据,数组的编号为1到100。第三个选择器视图具有一个数组,其中包含模型铁轨制造商的列表。我已经使用在此站点上找到的方法标记了选择器视图,但是当我运行该应用程序时,所有三个选择器视图的数据都为1到100。我还将控件从所有选择器视图拖到视图顶部的黄色圆圈,然后单击
dataSource委托 。如何在一个视图中使用具有不同数据源的多个选择器视图?另外,为了使代码运行,我不得不从所有 @IBOutlet中
删除 weak __与选择器视图有关的声明。 这是一件坏事吗?我对代码比较陌生。谢谢。

选择器视图场景屏幕截图

import UIKit

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
    //MARK: Properties

    @IBOutlet var layoutLengthPickerView: UIPickerView!
    @IBOutlet var layoutWidthPickerView: UIPickerView!
    @IBOutlet var trackPickerView: UIPickerView!

    override func viewDidLoad() {
        super.viewDidLoad()

        layoutLengthPickerView = UIPickerView()
        layoutWidthPickerView = UIPickerView()
        trackPickerView = UIPickerView()

        layoutLengthPickerView.tag = 0
        layoutWidthPickerView.tag = 1
        trackPickerView.tag = 2
    }

    let numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"]

    let manufacturers = ["Atlas True Track", "Atlas Code 100", "Atlas Code 83", "Bachmann Nickel Silver", "Bachmann Steel Alloy", "Kato", "Life-Like Trains Code 100", "LIfe-Like Trains Power-Loc", "Peco Code 100", "Peco Code 83", "Peco Code 75", "Shinohara Code 100", "Shinohara Code 70", "Walthers"]

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if pickerView.tag == 0 {
            return numbers[row]
        } else if pickerView.tag == 1 {
            return numbers[row]
        } else if pickerView.tag == 2 {
            return manufacturers[row]
        }

        return ""
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if pickerView.tag == 0 {
            return numbers.count
        } else if pickerView.tag == 1 {
            return numbers.count
        } else if pickerView.tag == 2 {
            return manufacturers.count
        }
        return 1
    }
}

问题答案:

在处理具有委托人和数据源的多个控件时,应考虑通过为多个选择器的委托创建单独的对象来避免视图控制器膨胀(即,按照单一职责原则的精神)。这使得这个逻辑出视图控制器本身,并避免了单一繁琐UIPickerViewDataSourceUIPickerViewDelegate努力服务的多个采摘与毛茸茸的方法if-
elseswitch语句。

例如,这是一个视图控制器,它具有两个拾取器的出口,但是您不必为视图控制器添加代码来管理dataSourcedelegate为这些拾取器而烦恼,您可以为每个拾取器拥有单独的对象,并且所有视图控制器要做的就是说哪个委托对象将处理哪个选择器:

class ViewController: UIViewController {

    @IBOutlet weak var namePicker: UIPickerView!
    @IBOutlet weak var numberPicker: UIPickerView!

    let namePickerDelegate = NamePickerDelegate()
    let numberPickerDelegate = NumberPickerDelegate()

    override func viewDidLoad() {
        super.viewDidLoad()

        namePicker.delegate = namePickerDelegate
        namePicker.dataSource = namePickerDelegate

        numberPicker.delegate = numberPickerDelegate
        numberPicker.dataSource = numberPickerDelegate
    }

    @IBAction func didTapButton(_ sender: Any) {
        let nameValue = namePicker.selectedRow(inComponent: 0)
        let numberValue = numberPicker.selectedRow(inComponent: 0)

        print("\(nameValue); \(numberValue)")
    }

}

唯一的技巧是确保对这些委托对象保持强烈的引用,如上所示,因为按照最佳做法,选择器本身对引用的委托仅具有较弱的引用。

Picker委托方法的实现更加简洁:

class NamePickerDelegate: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
    let names = ["Mo", "Larry", "Curley"]

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return names.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return names[row]
    }
}

class NumberPickerDelegate: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
    let numbers: [String] = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .spellOut
        return (0 ..< 100).compactMap { formatter.string(for: $0) }  // use `flatMap` in Xcode versions prior to 9.3
    }()

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return numbers.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return numbers[row]
    }
}

现在,显然,这仍然是一个简化的示例,但是美丽之处在于,随着代码变得越来越复杂,详细信息被封装在单独的对象中,而不是将所有代码都包含在单个视图控制器中。

如果需要,可以让视图控制器为委托/数据源对象提供字符串列表。实际上,这简化了它,因为对于选择器委托只需要一个类,而对于每个选择器只需实例化一个不同的类:

class ViewController: UIViewController {

    let names = ["Mo", "Larry", "Curley"]

    let numbers: [String] = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .spellOut
        return (0 ..< 100).compactMap { formatter.string(for: $0) }  // use `flatMap` in Xcode versions prior to 9.3
    }()

    @IBOutlet weak var numberPickerOne: UIPickerView!
    @IBOutlet weak var numberPickerTwo: UIPickerView!
    @IBOutlet weak var namePicker: UIPickerView!

    lazy var numberPickerOneDelegate: PickerDelegate = PickerDelegate(strings: self.numbers)
    lazy var numberPickerTwoDelegate: PickerDelegate = PickerDelegate(strings: self.numbers)
    lazy var namePickerDelegate:PickerDelegate = PickerDelegate(strings: self.names)

    override func viewDidLoad() {
        super.viewDidLoad()

        numberPickerOne.delegate   = numberPickerOneDelegate
        numberPickerOne.dataSource = numberPickerOneDelegate

        numberPickerTwo.delegate   = numberPickerTwoDelegate
        numberPickerTwo.dataSource = numberPickerTwoDelegate

        namePicker.delegate        = namePickerDelegate
        namePicker.dataSource      = namePickerDelegate
    }

}

class PickerDelegate: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
    let strings: [String]

    init(strings: [String]) {
        self.strings = strings
        super.init()
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return strings.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return strings[row]
    }
}


 类似资料:
  • 问题内容: 我正在制作一个有两个UIImageViews的应用程序。在每个图像视图中,用户需要能够输入不同的图像。这是我到目前为止的代码。 最终为每个不同的图像视图选择相同的图像。我希望能够选择两张单独的照片,每个视图一张。谢谢您的帮助。 问题答案: 您可以为每个按钮设置不同的标签,然后根据按钮的标签更新一个imageView或另一个。您只需要一个UIImagePickerController:

  • 我有一个带有背景图像和标题标题的viewcontroller。这种观点在大多数情况下都是一样的。我将在这个viewcontroller中显示和隐藏不同的子视图。 如何使用故事板实现这一点? 我是否必须为每个子视图创建单独的XIB 还是有其他优雅的解决方案? 谢谢

  • 我正在使用以下项目 https://github.com/akotoe/android-slide-out-menu.git开发滑出菜单应用程序。 如何通过单击幻灯片菜单中的列表在同一视图中运行不同的活动。 例如,如果我单击项目1,我想在一个单独的活动中解析一个XML文件,并将该活动作为子项添加到此父视图中。因为在每一项单击上,我希望解析一个单独的XML文件,并且我希望在一个单独的布局文件中表示解

  • 问题内容: 我正在尝试在具有多个视图控制器的Swift应用程序中使用。我的情节提要板(和)上有2个视图控制器,它们都嵌入各自的导航控制器中。它们具有情节提要标识符“ ”和“ ”。我在情节提要上还具有一个带有控制器的页面视图控制器,并将导航设置为水平和过渡样式以在属性检查器中滚动。是应用程序的根视图控制器 我想成为页面视图控制器的第一页,所以我这样编写了它的类: 的文件如下所示: 但是,当我运行我的

  • 问题内容: 我有这个数据库存储传感器采集数据, 采集(acq)来自不同控制单元(cu)的固定间隔(日期时间) 每个采集在数据表中存储了许多不同的度量 我需要这种观点: 作为: v1是data.value(例如湿度),其中 acq.id_cu = 1 AND data.id_meas = 100 v2是data.value(例如计数器),其中 acq.id_cu = 2 AND data.id_me

  • 如何从3个按钮中选择只有1个按钮?我设法设置/取消设置所选按钮的背景色。但无法选择唯一一个选定的按钮。 示例btn1、btn2、btn3。当我选择btn1时,btn1背景颜色发生变化,btn2和btn3不受影响。之后,当我再次选择btn2时,btn1背景色未设置,btn2背景色更改。因此此时选择btn2而不选择btn1和btn3。 下面是我的示例代码: