如何在 prepare(segue:) 的 switch 语句中使用可选绑定
How to use optional binding in switch statement in prepare(segue:)
在swift中,您可以使用prepare(segue:)
中switch语句的一个很酷的特性来根据目标视图控制器的类型创建案例:
示例:
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是由split view controller触发的,那么destination是一个navigation controller,而你真正想要做的是打开navigation controller的top view controller的class ?
我想做这样的事情:
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
和 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 语句不会真正被编译器验证为处理所有情况(因为您需要创建默认情况),因此使用 [=11= 没有任何额外好处] 而不仅仅是 if let
可选绑定并不真正适用于像您尝试做的那样的切换。
我理解使用开关而不是简单的 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"
}
}
在我看来,您应该使用 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()
}
您可能会发现此扩展很有用……
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
}
Not ?? destination
确保 return 值是非可选的,并且还允许它在 destination
也可能是非导航控制器的地方工作。
这个问题我想出了一个不错的解决方案。
它涉及在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
}
}
在swift中,您可以使用prepare(segue:)
中switch语句的一个很酷的特性来根据目标视图控制器的类型创建案例:
示例:
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是由split view controller触发的,那么destination是一个navigation controller,而你真正想要做的是打开navigation controller的top view controller的class ?
我想做这样的事情:
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
和 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 语句不会真正被编译器验证为处理所有情况(因为您需要创建默认情况),因此使用 [=11= 没有任何额外好处] 而不仅仅是 if let
可选绑定并不真正适用于像您尝试做的那样的切换。
我理解使用开关而不是简单的 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"
}
}
在我看来,您应该使用 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()
}
您可能会发现此扩展很有用……
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
}
Not ?? destination
确保 return 值是非可选的,并且还允许它在 destination
也可能是非导航控制器的地方工作。
这个问题我想出了一个不错的解决方案。
它涉及在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
}
}