如何从多个 Storyboard 源视图控制器中呈现给定的视图控制器?

Posted

技术标签:

【中文标题】如何从多个 Storyboard 源视图控制器中呈现给定的视图控制器?【英文标题】:How Can I Present A Given View Controller From More Than One Storyboard Source View Controller? 【发布时间】:2017-03-16 23:19:00 【问题描述】:

我正在制作一个故事板,因此我需要展示一个数据输入视图控制器。数据输入 vc 需要一个保存按钮和一个取消按钮。我需要展示来自其他两个视图控制器的数据条目 vc。

我想通过情节提要进行全部配置,以便我的情节提要确实“讲述故事”。如果我对数据输入 VC 进行显示 segue,则后退按钮将使我回到正确的源控制器(VC1 或 VC2)。我想我可以使用后退按钮来触发取消操作(嗯...),但是保存操作呢?如果我通过中间导航控制器以模态方式呈现数据输入 VC,那么我可以添加保存和取消栏按钮项目并将展开 segues 附加到它们,但似乎没有办法有条件地展开回正确的源( VC1 或 VC2)。

我决定的是:

    VC1 和 VC2 将在没有中间导航控制器的情况下以模态方式呈现数据输入 VC(即,数据输入 VC 没有导航项)。 数据输入vc会有两个UIButton,save和cancel。这两个按钮将触发数据输入 VC 中的操作,从而将其关闭。 VC1(VC2) 将向数据输入 VC 的按钮添加目标,以便 VC1(VC2) 可以采取适当的操作(包括删除目标)。

请参阅下面的代码和故事板。 (注意:这些不是来自我的实际应用程序。它们来自我用来试验的项目。

所以,我有什么作品。但是,我不禁觉得有一种更优雅的技术。我真正追求的是重用数据输入视图及其控制器。从所有者是数据输入 vc 的 nib 加载视图会起作用吗?也许是一个 UIContainerView?请有更多经验的人给我建议(如果甚至确认我所拥有的东西已经足够好了)?谢谢!

VC1和VC2中的相关代码:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) 

    func setupButtons(_ view: UIView) 
        view.subviews.forEach()  view in
            if let button = view as? UIButton, let title = button.title(for: .normal) 
                switch title 
                case "Save":
                    button.addTarget(self, action: #selector(save(sender:)), for: .touchUpInside)
                case "Cancel":
                    button.addTarget(self, action: #selector(cancel(sender:)), for: .touchUpInside)
                default:
                    break
                

            
            else 
                setupButtons(view)
            
        
    

    if let vc = segue.destination as? DataEntryViewController 
        setupButtons(vc.view)
    



func cancel(sender: UIButton) 
    process(button: sender, save: false)


func save(sender: UIButton) 
    process(button: sender, save: true)


private func process(button: UIButton, save: Bool) 
    let title = button.title(for: .normal) ?? "<unknown>"
    print("The \(title) button was pressed")

    if save 
        if let vc = button.viewController as? DataEntryViewController 
            print("The data is \(vc.data)")
        
        else 
            print("Cannot get the \(title) button's VC")
        
    

    button.removeTarget(self, action: nil, for: .touchUpInside)

数据输入控制器中的相关代码:

@IBAction func cancel(_ sender: UIButton) 
    self.dismiss(animated: true, completion: nil)


@IBAction func save(_ sender: UIButton) 
    self.dismiss(animated: true, completion: nil)

【问题讨论】:

【参考方案1】:

根据我对 unwind segues 的了解,这应该可以。见Technical Note TN2298 “Unwind Segue 如何确定其目标视图控制器”部分。您是否真的尝试在 VC1 和 VC2 中实现相同的展开操作 并将按钮连接到 Interface Builder 中相应的展开操作?

作为旁注,您可能应该在查找视图时使用标签,而不是将按钮标题与固定字符串(国际化和所有)进行比较。

编辑:

我刚刚创建了一个测试项目,完全符合我的描述。该应用程序是一个标签栏控制器,带有两个视图控制器(FirstViewControllerSecondViewController),它们都提供了一个带有取消按钮和保存按钮的数据输入视图控制器。它们分别与unwindToCancel:unwindToSave: 的展开操作相关联。

class FirstViewController: UIViewController

    @IBAction func unwindToSave(_ segue: UIStoryboardSegue)
    
        print("FirstViewController unwindToSave")
    

    @IBAction func unwindToCancel(_ segue: UIStoryboardSegue)
    
        print("FirstViewController unwindToCancel")
    


class SecondViewController: UIViewController

    @IBAction func unwindToSave(_ segue: UIStoryboardSegue)
    
        print("SecondViewController unwindToSave")
    

    @IBAction func unwindToCancel(_ segue: UIStoryboardSegue)
    
        print("SecondViewController unwindToCancel")
    

根据我来自哪个视图控制器,当我点击取消或保存时会打印正确的消息。

【讨论】:

天啊!那行得通!我曾经说服自己,认为每个展开方法都必须唯一命名:现在我知道得更好了。非常感谢!将在标签上做。 不客气。这就是响应者链的美妙之处。当我第一次发现它时,我有同样的“OMG 时刻”:)。我用插图和示例代码对我的答案进行了拉皮条,很高兴您可以在此期间验证它。

以上是关于如何从多个 Storyboard 源视图控制器中呈现给定的视图控制器?的主要内容,如果未能解决你的问题,请参考以下文章

iOS如何获取对带有segue的storyboard容器中嵌入的视图控制器的引用?

xCode swift Storyboard 单视图控制器,内部有多个/动态视图

在IOS的Storyboard中隐藏子视图

如何从自定义视图控制器类加载初始视图控制器

如何通过编码管理 .storyboard 或 .xib 文件中的多个视图。?

如何添加从启动屏幕到初始视图控制器 ios 的过渡?