【问题标题】:Possible to perform segue without the use of StoryBoard?可以在不使用 StoryBoard 的情况下执行 segue 吗?
【发布时间】:2018-06-16 23:58:14
【问题描述】:

到目前为止,我一直在完全以编程方式创建我的 Swift 项目。我已经创建了详细的导航控制器和表格视图控制器,而无需接触 StoryBoard (SB) 一次。我已经到了想将数据从 TableViewCell 单击传递到另一个 ViewController 的地步,但是,我相信我需要使用 segue 并在 SB 内部创建/识别它。由于这个应用程序随着时间的推移变得相当复杂,因此模仿 SB 内部的所有视图控制器变得非常困难,并且在 SB 内部创建任何更改都不会反映模拟器上视图内部的任何更改(我有将SB内部的视图与它们各自的类配对,但没有任何效果。当标识符匹配时,即使是segue也没有被识别)。因此,我有几个问题。

  1. 是否可以通过编程方式执行 segue?换句话说,是否可以在不触及情节提要的情况下将数据从一个视图控制器传递到另一个视图控制器?

  2. 是否有可以遵循的简单指南或技术来在 StoryBoard 中模仿他们的代码?使用简单的应用程序,应该不会太难。但是,如果有人完全以编程方式创建应用程序,还有其他方法可以在 StoryBoard 中描绘应用程序吗?

【问题讨论】:

  • 查看this link。它可能会给你一些建议。
  • 感谢@vadian 和@iabuseservers 的帮助。对于其他可能遇到这些问题的人,我建议您也查看此视频!再次感谢。视频:youtube.com/watch?v=70OhFMzRBZM

标签: ios swift xcode storyboard segue


【解决方案1】:

Interface Builder (IB) 只是一个用于程序开发的 GUI。您在 IB 中可以做的任何事情都绝对可以通过编程方式完成,但并非所有您可以通过编程方式在 IB 中完成的事情,因为 IB 只是用于界面构建——而且只是一些界面构建,而不是全部。

segue 只是 IB 术语。在 iOS 中,您只能以三种方式显示视图控制器:push(通过UINavigationController)、present(通过演示对象供应商UIViewControllerTransitioningDelegate)或show(一种更通用的显示视图的方法控制器)。

由于您不熟悉程序化 iOS 开发(最好的一种,IMO),所以快速 101:

class ProgrammaticViewController: UIViewController {

    override func loadView() {

        // do not call super.loadView()
        // most IB developers don't even know this method exists
        //   because this is where IB does its work
        // add all of your view objects here (scroll views,
        //   table views, buttons, everything)

        setView()
        addTableView()
        ...

    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // do call super.viewDidLoad(), however
        // do your post-view setup here, like adding observers
        //   or fetching data
        // this method is called after the entire view
        //   has been loaded into memory so consider that

    }

    // other lifecycle events that come after viewDidLoad where you
    //   can perform last-second work include viewDidLayoutSubviews(),
    //   viewWillAppear(), viewDidAppear(), etc.

    deinit {
        // do any cleanup here like deactivating timers, removing
        //   observers, etc.
    }

    // MARK: Methods

    func setView() {

        // if you're creating your view controller programmatically,
        //   you must create the view controller's actual view property
        //   and it must be done before adding any subviews to the
        //   view controller's view

        view = UIView()
        view.frame = UIScreen.main.bounds
        view.backgroundColor = UIColor.white

    }

}

如果您使用自动布局(并且您可能应该这样做),您并不总是需要使用view.frame = UIScreen.main.bounds 显式设置视图的框架。如果它是应用程序的根视图控制器,则不需要它——窗口拥有该视图控制器,它会设置框架。如果您随后将UINavigationController 放在根目录中并且您正在使用自动布局,那么您推送的所有视图控制器都不需要它们的框架集。因此,您需要使用view.frame = UIScreen.main.bounds 之类的东西显式设置视图框架的唯一实时是当您以模态方式呈现视图控制器时。这是因为模态呈现的视图控制器不属于窗口或导航控制器;它暂时存在于瞬态容器视图中。在这种情况下,您必须设置它的框架。

以编程方式传递数据比 IB 开发人员更简单。只需实例化一个视图控制器,用一个值注入它的一个(非私有)属性,然后推送、呈现或显示它。以下是 UITableView 代表 didSelectRowAt 的样子:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let p = indexPath.row
    let detailViewController = SomeDetailViewController()

    detailViewController.someProperty = searchResults[p]
    navigationController?.pushViewController(detailViewController, animated: true)

}

这显然是可行的,因为您已经在该视图控制器中创建了该属性,并且没有给它一个私有访问修饰符。

class SomeDetailViewController: UIViewController {

    var dataObject: SomeType? // injectable
    private var notInjectable: SomeType?

}

更新: 就 Apple 而言,IB 显然不是 iOS 开发的未来,因为 SwiftUI 的引入是另一种以编程方式开发 iOS 的方式。就个人而言,我讨厌 GUI 编程,我很高兴看到它慢慢被淘汰。

【讨论】:

  • 好先生...非常感谢。你不仅解释了我的问题,我还得到了一个很棒的概述,它将永远伴随着我。一切都很清楚而且很有帮助,但有一个简单的问题:我看到在“setView()”函数内部,您已将“view.frame”声明为“UIScreen.main.bounds”。 view.frame 不是已经设置为 Screen 的主要边界了吗?换句话说,我通常不声明,如果我想要一些视图来拉伸整个屏幕,我声明它的宽度和高度为:view.frame.width 和 view.frame.height(分别)。换句话说,有必要吗?谢谢
  • 如果您要进行纯编程,则必须在某处设置视图控制器的框架。但并不是每个视图控制器都需要在其内部设置view.frame = UIScreen.main.bounds。例如,子视图控制器可以让其视图的框架由其父设置。根视图控制器也不需要设置它,因为它归UIWindow 所有,您在AppDeleagte 中使用window = UIWindow(frame: UIScreen.main.bounds) 设置了它的框架。但这是当您使用纯程序化时,您已删除情节提要文件并重新配置您的应用程序以不启动它。
  • 如果您仍然愿意提供帮助,还有另一个问题:当数据被推送到变量“dataObject”时,我如何使用该变量来描绘,比如说,在标签内?因为每当我尝试访问该变量的值时,都会收到以下错误:实例成员“dataObject”不能用于类型“”。有什么想法吗?
【解决方案2】:

是否可以通过编程方式执行转场?

当然。 UIStoryboardSegue 具有可用于创建 segue 的初始化程序,并且它具有 perform() 方法,您可以调用该方法使 segue 完成它的工作。但转场主要是一种工具,可以更轻松地在情节提要中的场景之间进行转换,因此如果您一开始不使用情节提要,就没有理由这样做。

换句话说,是否可以在不触及情节提要的情况下将数据从一个视图控制器传递到另一个视图控制器?

再次,是的。故事板在 iOS 5 之前甚至不存在,你可以打赌人们在此之前就已经在编写具有视图控制器之间转换的应用程序了。你已经得到的关于如何做到这一点的答案很好。不过,更一般地说,视图控制器只是对象,向另一个控制器发送信息所需的只是对目标控制器的有效引用。

但是,如果有人完全以编程方式创建应用程序,还有其他方法可以在 StoryBoard 中描绘应用程序吗?

如果您的意思是要切换到使用情节提要,那么是的,有一些很好的方法可以做到这一点。如果您的意思是您想以某种方式在情节提要中以编程方式表示您的应用正在执行的操作,但继续以编程方式执行所有操作,那么不,没有办法做到这一点(而且这样做真的没有意义)。

过渡到情节提要不一定是全有或全无。您可以在情节提要中仅建模一个视图控制器,并根据需要使用init(name:bundle:)(初始化情节提要)和instantiateViewController(withIdentifier:)(加载特定视图控制器)加载它,然后以与您相同的方式使用该视图控制器现在做。然后可以删除用于设置该视图控制器及其视图层次结构的所有代码,因为您现在是从情节提要中加载它。完成后,对其他视图控制器重复该过程,展开故事板并根据需要删除设置代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 2013-02-17
    相关资源
    最近更新 更多