你能在集合中找到一个类型的第一个实例,并将该实例作为具体类型返回吗?

时间:2018-03-07 22:53:37

标签: swift casting flatmap

这段代码困扰我。下面,我试图在NavigationController的堆栈中找到特定类型的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不这样做。

那么还有另一种解决这个问题的方法吗?

2 个答案:

答案 0 :(得分:1)

我赞成合并Tlazy以获得有条件地投射到func popToFirstViewController<T:UIViewController>(ofType type:T.Type, animated:Bool) -> T? { guard let foundViewController = viewControllers.lazy.flatMap({ $0 as? T }).first { return nil } self.popToViewController(foundViewController, animated:animated) return foundViewController } 的行为,消除不匹配,枚举整个数组:

flatMap

至于那些阅读代码的人会感到困惑:&#34; cols是相当惯用的Swift,与upcoming rename to compactMap相比不那么模糊。如果您所在环境中的读者确实遇到问题,您可以随时编写一个小帮手(通用或非通用),以更清晰的名称执行相同的工作。

答案 1 :(得分:1)

您可以使用案例模式选择您感兴趣的类型的viewControllers,然后弹出并返回您找到的第一个:

SELECT CON
FROM
(
SELECT 1 as SEQ, 0 as NR, NAME ,TEMP.CON1 as CON
FROM (
    SELECT NAME, CONCAT(NAME,'(', LEFT(OCCUPATION, 1),')') AS CON1
    FROM OCCUPATIONS
    ORDER BY NAME -- don't need 
    ) AS TEMP
UNION
SELECT 2, NR, null, TEMP2.CON2 
FROM (
    SELECT COUNT(*) AS NR, CONCAT('THERE ARE A TOTAL OF ', COUNT(OCCUPATION),' ', OCCUPATION, 's') AS CON2
    FROM OCCUPATIONS
    GROUP BY OCCUPATION
    ORDER BY NR, OCCUPATION -- don't need
) AS TEMP2 ) T 
ORDER BY SEQ, NR, NAME, CON

示例:

使用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" }

您可能还希望将函数弹出到类型的最新viewController。只需简单修改(添加popToLastViewController(ofType:animated:)):

即可轻松实现
.reversed()