你们都可以在集合中找到一个类型的第一个实例,并将该实例作为具体类型返回吗?
Can you both find a first instance of a type in a collection, returning that instance as that concrete type?
这段代码让我很困扰。下面,我试图在 NavigationController 的堆栈中找到特定类型 ViewController 的第一个实例。简单的。但是当我找到它时,我必须将它转换为我刚刚寻找的类型,这对我来说似乎是多余的。
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
guard let foundViewController = viewControllers.first(where: { [=10=] 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({ [=11=] as? T }).first() else {
return nil
}
self.popToViewController(foundViewController, animated:animated)
return foundViewController
}
...但我反复发现像这样使用 flatMap
会使阅读代码的人感到困惑,并且正如下面的评论中正确指出的那样,它会遍历整个集合,而 first
不会那样做。
那么还有其他方法可以解决这个问题吗?
我赞成组合 flatMap
和 lazy
以获得有条件地转换为 T
的行为,去除不匹配,并且 not 枚举整个数组:
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
guard let foundViewController = viewControllers.lazy.flatMap({ [=10=] as? T }).first {
return nil
}
self.popToViewController(foundViewController, animated:animated)
return foundViewController
}
至于 "confusing people that read the code:" flatMap
是相当地道的 Swift,并且与 upcoming rename to compactMap
会更不歧义。如果您的环境中的读者真的有问题,您总是可以编写一个小助手(通用或非通用)以更清晰的名称执行相同的工作。
您可以使用 case patterns 来 select 您感兴趣的类型的 viewController 并且 pop 和 return 第一个你找到一个:
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
到 return 到 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
}
这段代码让我很困扰。下面,我试图在 NavigationController 的堆栈中找到特定类型 ViewController 的第一个实例。简单的。但是当我找到它时,我必须将它转换为我刚刚寻找的类型,这对我来说似乎是多余的。
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
guard let foundViewController = viewControllers.first(where: { [=10=] 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({ [=11=] as? T }).first() else {
return nil
}
self.popToViewController(foundViewController, animated:animated)
return foundViewController
}
...但我反复发现像这样使用 flatMap
会使阅读代码的人感到困惑,并且正如下面的评论中正确指出的那样,它会遍历整个集合,而 first
不会那样做。
那么还有其他方法可以解决这个问题吗?
我赞成组合 flatMap
和 lazy
以获得有条件地转换为 T
的行为,去除不匹配,并且 not 枚举整个数组:
func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? {
guard let foundViewController = viewControllers.lazy.flatMap({ [=10=] as? T }).first {
return nil
}
self.popToViewController(foundViewController, animated:animated)
return foundViewController
}
至于 "confusing people that read the code:" flatMap
是相当地道的 Swift,并且与 upcoming rename to compactMap
会更不歧义。如果您的环境中的读者真的有问题,您总是可以编写一个小助手(通用或非通用)以更清晰的名称执行相同的工作。
您可以使用 case patterns 来 select 您感兴趣的类型的 viewController 并且 pop 和 return 第一个你找到一个:
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
到 return 到 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
}