这个密码让我很困扰。下面,我试图在导航控制器堆栈中找到特定类型viewcontroller的第一个实例。很简单。但当我找到它时,我必须把它转换成我刚刚寻找的类型,这对我来说似乎是多余的。
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
guard let foundViewController = viewControllers.first(where: { $0 is T }) as? T else {
return nil
}
self.popToViewController(foundViewController, animated:animated)
return foundViewController
}
我唯一能想到的是…
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
guard let foundViewController = viewControllers.flatMap({ $0 as? T }).first() else {
return nil
}
self.popToViewController(foundViewController, animated:animated)
return foundViewController
}
……但我反复发现,像这样使用
flatMap
会让阅读代码的人感到困惑,正如下面注释中正确指出的那样,它会遍历整个集合,而first
不会这样做。那么,有没有别的办法来解决这个问题呢?
最佳答案
您可以使用case模式选择感兴趣类型的viewcontrollers,然后弹出并返回找到的第一个viewcontrollers:
extension UINavigationController {
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
for case let vc as T in viewControllers {
self.popToViewController(vc, animated: animated)
return vc
}
return nil
}
}
例子:
使用
OrangeViewController
中的按钮返回堆栈中前面的GreenViewController
:@IBAction func popToGreen(_ sender: UIButton) {
let greenVC = self.navigationController?.popToFirstViewController(
ofType: GreenViewController.self,
animated: true
)
// Modify a property in GreenViewController that
// will be moved into a label in viewWillAppear
greenVC?.labelText = "Returned here from Orange"
}
popToLastViewController(ofType:animated:)
您可能还希望函数弹出到某个类型的最新viewcontroller。通过简单的修改(添加
.reversed()
)即可轻松实现:func popToLastViewController<T:UIViewController>(ofType type:T.Type, animated: Bool) -> T? {
for case let vc as T in viewControllers.reversed() {
self.popToViewController(vc, animated: animated)
return vc
}
return nil
}