3

在 swift 中,您可以使用 switch 语句的一个很酷的功能来根据目标视图控制器的类型prepare(segue:)创建案例:

例子:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch segue.destination {

    case let detailViewController as DetailViewController:
      detailViewController.title = "DetailViewController"
    }
    case let otherViewController as OtherViewController:
      otherViewController.title = "OtherViewController"
    }
}

但是,如果 segue 是由拆分视图控制器触发的,那么目的地是导航控制器,而您真正想要做的是打开导航控制器的顶部视图控制器的类呢?

我想做这样的事情:

case let nav as UINavigationController,
     let detailViewController = nav.topViewController as? DetailViewController:
    //case code goes here

我在多部分if let可选绑定中使用的构造相同。

那是行不通的。相反,我必须像这样做一个相当痛苦的构造:

case let nav as UINavigationController
  where nav.topViewController is DetailViewController:
  guard let detailViewController = nav.topViewController as? DetailViewController
    else {
      break
  }
  detailViewController.title = "DetailViewController"

这行得通,但它似乎不必要地冗长,并且模糊了意图。在 Swift 3 中这样的 switch 语句的情况下,有没有办法使用多部分可选绑定?

4

5 回答 5

1

你可能会发现这个扩展很有用……</p>

extension UIStoryboardSegue {
    var destinationNavTopViewController: UIViewController? {
        return (destination as? UINavigationController)?.topViewController ?? destination
    }
}

然后你可以简单地……</p>

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch segue.destinationNavTopViewController {
    case let detailViewController as? DetailViewController:
        // case code goes here
}

不是?? destination确保返回值是非可选的,并且还允许它在destination也可能是非导航控制器的地方工作。

于 2018-09-17T10:18:40.407 回答
1

我为这个问题制定了一个不错的解决方案。

它涉及在 switch 语句之前进行一些设置,然后在 switch 语句中使用元组。看起来是这样的:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let dest = segue.destination
    let navTopVC = (dest as? UINavigationController)?.topViewController
    switch (dest, navTopVC) {

    case (_, let top as VC1):
        top.vc1Text = "Segue message for VC1"

    case (_, let top as VC2):
        top.vc2Text = "Segue message for VC2"

    case (let dest as VC3, nil):
        dest.vc3Text = "Segue message for VC3"

    default:
        break
    }
}
于 2018-09-17T17:33:44.880 回答
1

我不认为有办法用switchand来做到这一点case,但是你可以用 and 做一些更接近你正在寻找的东西ifcase更新:正如 Hamish 指出的,case这种情况甚至不需要)或者只是正常的if let

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

    if let nav = segue.destination as? UINavigationController, 
        let detailViewController = nav.topViewController as? DetailViewController {
        detailViewController.title = "DetailViewController"
    }

    if let otherViewController? = segue.destination as? OtherViewController {
        otherViewController.title = "OtherViewController"
    }
}

由于此示例中的 switch 语句实际上不会被编译器验证为处理所有情况(因为您需要创建默认情况),因此使用switch而不是仅仅使用没有额外的好处if let

于 2016-11-17T17:07:47.653 回答
0

在我看来,您应该使用 segue 标识符来控制此开关中的流量。但是要回答您的问题,这应该对您有用。

switch (segue.destination as? UINavigationController)?.topViewController ?? segue.destination {
    ...
}

问题是,根据语法,案例项目列表中的每个项目只有一个模式(在你的情况下它是绑定的)。由于您在输入中只有一个项目,但想使用两种模式,您要么想规范化输入(在这种情况下,如上所示),要么扩展项目列表(在这种情况下不合适,但我展示了一个下面的例子)。

switch ((segue.destination as? UINavigationController)?.topViewController, segue.destination) {
case (let tvc, let vc) where (tvc ?? vc) is DetailViewController:
    // TODO: If you await your DetailViewController in navigation or without.
    break
case (let tvc as DetailViewController, _):
    // TODO: If you await your DetailViewController in navigation but other vc is not in a navigation vc.
default:
    fatalError()
}
于 2017-03-14T12:39:33.837 回答
0

可选绑定并不真正适合您尝试执行的开关。

我理解使用开关的愿望,而不是简单的 if 和 if else,但它在概念上与 switch 的意图有点不同。

无论如何,这是我在大多数情况下使用的两个选项

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

    switch segue.destination {
    case is DetailViewController:
        segue.destination.title = "DetailViewController"
    case is OtherViewController:
        segue.destination.title = "OtherViewController"
    default:
        break
    }
}

或者

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

    if let controller = seuge.destination as? DetailViewController {
        controller.title = "DetailViewController"
    }
    else if let controller = seuge.destination as? OtherViewController {
        controllercontroller.title = "OtherViewController"
    }
}
于 2016-11-17T17:23:10.240 回答