swift 如何在prepare的switch语句中使用可选绑定(segue:)

0lvr5msh  于 2022-02-21  发布在  Swift
关注(0)|答案(5)|浏览(137)

在swift中,你可以使用prepare(segue:)中switch语句的一个很酷的特性,根据目标视图控制器的 type 创建case:
示例:

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语句?

2w3rbyxf

2w3rbyxf1#

我想出了一个解决这个问题的好办法。
它包括在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
    }
}
0ejtzxu1

0ejtzxu12#

您可能会发现此扩展非常有用...

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

然后你就可以...

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

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

z9zf31ra

z9zf31ra3#

我不认为switchcase有办法做到这一点,但您可以使用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没有任何额外的好处

omqzjyyz

omqzjyyz4#

可选绑定并不像您所尝试的那样真正适用于开关。
我理解使用开关而不是简单的if和if else的愿望,但是这在概念上与开关的目的有点不同。
无论如何,这里是我在大多数情况下使用的两个选项

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"
    }
}
1qczuiv0

1qczuiv05#

在我看来,你应该使用segue标识符来控制这个交换机中的流。但是回答你的问题,这应该对你有效。

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

问题是,根据语法,在case项目列表中,每个项目只有一个模式(在本例中,它是绑定的)。由于输入中只有一个项目,但希望使用两个模式,因此,您要么希望规范化输入(在本例中,这是合适的,如上文所示),要么希望扩展项目列表(在本例中,这是不合适的,但我在下面给出了一个示例)。

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()
}

相关问题