这个密码让我很困扰。下面,我试图在导航控制器堆栈中找到特定类型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
}

10-06 09:20
查看更多