本文介绍了如何在 swift 5 xcode 10 中创建在多个视图中使用的单例视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个选择器 (UIPickerView),我认为它应该是一个可以在多个视图中显示的单例.我正在使用选项卡式 UI,其中 2 个视图使用相同的选择器.如何创建选择器的一个实例,以便在数据更改时调用 reloadAllComponents 并让两个视图显示相同的选择?一次只有一个视图可见/活动.

I have a picker (UIPickerView) that I think should be a singleton that will be displayed in more than one view. I am using a tabbed UI and 2 of the views use the same picker. How I can create one instance of the picker so that I can call reloadAllComponents on it when the data changes, and have both views show the same selection? only one view is visible/active at a time.

除了选择器之外,公共标题中还会有其他控件.我从带有选择器和按钮的 xib 创建了一个视图.我可以把它放在故事板的 2 个视图上.

In addition to the picker, there will be other controls in that common header. I have created a view from an xib that has the picker and also a button. I can place that on the 2 views in the storyboard.

// This is the view that is placed on each of the viewcontrollers
class RaceSelView: UIView {

    @IBOutlet var view: UIView!
    @IBOutlet weak var racePicker: RacePicker!
// racePicker is UIPickerView with delegates to supply the data

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
// I assume the racePicker is instantiated in UINib, but how do I override it so that I can return the singleton racePicker?
        UINib(nibName: "RaceSelView", bundle: nil).instantiate(withOwner: self, options: nil)

        addSubview(view) // I really don't understand this. Aren't I setting this view to be a subview of itself?

        racePicker.setDelegates() // RacePicker supplies its own delegates and gets data from globals

        globals.racePicker = racePicker // globals needs a reference so that it can call racePicker.reloadAllComponents() when the data changes, but right now there are 2 instances and therefore only one gets notified

        racePicker.setCurRace() // this sets the picker to the current value, but this is rather useless because each instance only hits this code once, not every time the view becomes active. If the picker is changed in one view, the other view shows the wrong value
        view.bounds = self.bounds
    }

    @IBAction func onReload(_ sender: Any) {
        getRaces()
    }
}

它绘制并且没有例外,但是该选择器有2个实例,因此它们不协调.当一个改变时,另一个应该改变.我的直觉是让它成为单例,但我现在不知道如何覆盖它的创建以返回单例.

It draws and there are no exception, but there are 2 instances of that picker and therefore they are not coordinated. When one changes, the other should change. My instinct is to make it a singleton, but I don't now how to override its creation to return the singleton.

我设法通过创建一个 UIPickerView 单例来做到这一点,然后在视图控制器中为 2 个选项卡式视图中的每一个:

I managed to do this by creating a UIPickerView singleton, then in the view controller for each of the 2 tabbed views:

override func viewDidLoad() {
    super.viewDidLoad()

    addSubView(globals.theRacePicker)
}

这似乎工作得很好.我的理解是该视图不能一次位于 2x 位置,因此 addSubView 在将其分配给新视图之前将其从另一个中删除.问题是我想要一个在 2 之间共享的更复杂的标题视图,并希望使用 GUI 来定义它.我会看看我是否可以在运行时将选择器添加到标题的子视图中....

This seemed to work just fine. My understanding is that the view cannot be in 2x places at once, so addSubView removes it from the other before assigning it to the new. The problem is that I wanted a more complex header view that is shared between the 2 and wanted to use the GUI to define it. I will see if I can add the picker at runtime to the subview of the header....

推荐答案

我想我会发布我自己问题的答案.我创建了一个从 xib 加载的标题视图 (RaceSelView),其中包含多个控件.在您希望单例选择器出现的两个视图中创建一个 UIView.标题视图位于该位置.每当更改选项卡或加载控制器视图时,找到该视图并将单例选择器添加为子视图.

I thought I would post the answer to my own question. I created a header view (RaceSelView) that loads from xib that has several controls in it. Make a UIView in both views where you want the singleton picker to appear. The header view is placed at that location. Whenever the tab is changed, or the controllerviews are loaded, find that view and add the singleton picker as a subview.

protocol HasHeader {
    func getHeaderLoc() -> UIView
    func reload()
}
class BaseXCView: UIViewController,HasHeader {

    override func viewDidAppear(_ animated: Bool) {
        setRacePicker() // after layout has happened so that the headerLoc will be positioned correctly
        reload()
    }
    func setRacePicker() {
        var hv = globals.raceSelView
        if hv == nil {
            hv = RaceSelView(frame: getHeaderLoc().frame)
            globals.raceSelView = hv
        }
        view.addSubview(hv!)
    }
    func reload() {
        fatalError("Must Override")
    }
    func getHeaderLoc() -> UIView {
        fatalError("Must Override")
    }
}

class XCTabBarController: UITabBarController, UITabBarControllerDelegate {
    override func viewDidLoad() {
        self.delegate = self
    }
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
// this is called whenever the tab changes
        if let vc = viewController as? BaseXCView {
            vc.setRacePicker()
        }
    }
}

这似乎比单独的选择器实例更好.另一种方法是在每个实例变为活动状态时将状态复制到/从每个实例复制,并跟踪哪个是活动的,以便知道在基础数据发生变化时应该重新加载/重绘哪个.

This seems better than having separate instances of the picker. The alternative would involve copying the state to/from each instance when they become active, and keeping track of which is active in order to know which one to tell to reload/redraw when the underlying data changes.

我不确定这是最好的方法,欢迎评论.

I am not certain this is the best approach, comments are welcome.

这篇关于如何在 swift 5 xcode 10 中创建在多个视图中使用的单例视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-24 13:17