如何在准备中的 switch 语句中使用可选绑定(segue :)
Posted
技术标签:
【中文标题】如何在准备中的 switch 语句中使用可选绑定(segue :)【英文标题】:How to use optional binding in switch statement in prepare(segue:) 【发布时间】:2016-11-17 16:33:16 【问题描述】:在 swift 中,您可以使用prepare(segue:)
中 switch 语句的一个很酷的功能来根据目标视图控制器的 type 创建案例:
例子:
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 语句的情况下,有没有办法使用多部分可选绑定?
【问题讨论】:
从 switch 语句中删除where
子句意味着这种情况会将 any 捕获到导航控制器,这不是我需要的。我正在寻找一种在 switch 语句的情况下进行多部分可选绑定的方法。
哎呀,是的,你完全正确。
通常的做法是开启segue的identifier。
【参考方案1】:
我认为 switch
和 case
没有办法做到这一点,但你可以用 if
和 case
做一些更接近你正在寻找的事情(更新:正如 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
【讨论】:
if case let nav?
在 switch 语句之外是什么意思?
或者只是if let nav = segue.destination as? UINavigationController, ...
@DuncanC if case
在 if 语句中执行模式匹配,nav?
的模式是 optional pattern。当结果为非零时,它与表达式segue.destination as? UINavigationController
匹配(它被解包并绑定到nav
)。尽管这在功能上与可选绑定完全相同。【参考方案2】:
你可能会发现这个扩展很有用……
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
也可能是非导航控制器的地方工作。
【讨论】:
不错的解决方案。不过,请参阅我的自我回答。我认为它更灵活,并且更明确地说明了正在发生的事情。【参考方案3】:我为这个问题找到了一个不错的解决方案。
它涉及在 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
【讨论】:
【参考方案4】:可选绑定并不真正适合您尝试执行的开关。
我理解使用 switch 的愿望,而不是简单的 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"
【讨论】:
感谢您的意见,但我不同意。case let xx as class
非常适合这种情况。它甚至是量身定做的。看看我的问题中的第一个代码块。该语法允许您打开目标视图控制器的类并同时进行可选绑定。
这里的复杂因素是,如果目的地是导航控制器,我真的想根据目的地视图控制器的顶视图控制器的类进行切换。
但是您并没有根据变量的值进行切换,您只是在创建新变量。等同于 if-let
我可以想象它会在某个时候被添加,但这违背了当前的 switch 语句理念
不,它与if let
不同。它实际上是根据目标视图控制器的 CLASS 进行切换,并在这种情况下创建一个适当类型的局部变量,一次完成。真的。【参考方案5】:
在我看来,您应该使用 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()
【讨论】:
以上是关于如何在准备中的 switch 语句中使用可选绑定(segue :)的主要内容,如果未能解决你的问题,请参考以下文章