CI codecov.io Platform CocoaPods Compatible Swift Package Manager compatible Packagist

Ariadne

Ariadne 的线,以 Ariadne 的传说命名,指的是通过详尽地将逻辑应用于所有可用的路径来解决具有多种明显进行方式的问题 - 例如物理迷宫、逻辑难题或道德困境。

维基百科

Ariadne 是一个可扩展的路由框架,其构建考虑了组合和依赖注入原则。 它有助于创建过渡和路由,从而抽象出视图控制器的构建和呈现逻辑,使其可重用且紧凑。

动机

UIKit 存在路由问题。 所有视图控制器的呈现和解除方法都发生在视图控制器中,这通常会导致视图控制器过于臃肿,因为所有视图控制器的构建、依赖注入和过渡也都发生在那里。

这导致了大量的视图控制器,这些控制器无法轻易地进行测试,并且代码很难在不同的视图控制器实例中重复使用。 解决这些问题的一种方法是将视图控制器的构建和过渡代码分离到单独的对象中,通常称为 Router。 即使只有像 VIPER 这样的架构才将 Router 推广为必需组件,但我认为任何其他架构的应用程序都可以通过至少某种形式的路由得到极大的改进。

这就是 Ariadne 的用武之地。 这是一个框架,它提供视图控制器构建机制、过渡和路由类,以架构无关的方式从视图控制器中抽象出所有这些逻辑。

示例

假设您需要在一个 UINavigationController 中呈现用户个人资料。 通常,在没有任何库的 MVC 应用程序中,您会这样做

let storyboard = UIStoryboard(named: "User", bundle: nil)
let userController = storyboard.instantiateViewController(withIdentifier: "UserViewController")
userController.user = user
let navigation = UINavigationController(rootViewController: userController)
present(navigation, animated: true)

使用 Ariadne,此代码不再绑定到当前的视图控制器,并且可以如下所示

let route = Storyboards.User.userViewController.builder.embeddedInNavigation().presentRoute()
router.navigate(to: route, with: user)

注意:此特定示例需要 SwiftGen 集成,请参阅 SwiftGen 集成 指南。如果没有 SwiftGen,Storyboards.User.userViewController.builder 可以被任何自定义视图控制器构建器替换。

要求

安装

Swift Package Manager(需要 Xcode 11)

CocoaPods

pod 'Ariadne'

概述

Ariadne 架构从根本上从 ViewBuilder 开始。 因为视图控制器与 iOS 上的视图紧密耦合,所以 UIViewController 被认为是视图,并且类型别名为 ViewController

注意:在 watchOS 上,ViewControllerWKInterfaceController 的类型别名,在 macOS 上是 NSViewController 的类型别名,原因类似。

ViewBuilder 的定义很简单 - 它根据提供的 Context 构建一个 ViewController

protocol ViewBuilder {
    associatedtype ViewType: ViewController
    associatedtype Context
    func build(with context: Context) throws -> ViewType
}

开箱即用,Ariadne 为以下内容提供构建器

框架的第二个构建块是 ViewTransition 对象,它用于在视图之间执行过渡。 开箱即用,支持以下过渡

ViewBuilderViewTransition 对象可以组合在一起以形成可执行的 Route。 例如,给定 AlertBuilder,以下是如何使用 Ariadne 创建警报路由

let alertRoute = AlertBuilder().presentRoute()

请注意,presentRoute 方法对于 AlertBuilder 和任何 UIViewController 构建器都是以相同的方式调用的。 通过利用 ViewBuilder 上的协议扩展,任何过渡和路由都可以在 ViewBuilder 实例上重用。 要查看如何实现和扩展 ViewBuilder 协议的示例,请参阅 实现视图构建器 指南。

最后但并非最不重要的是,Router 对象将所有内容联系在一起,并允许您实际执行路由

router.navigate(to: alertRoute, with: alertModel, completion: { _ in
    // Route has completed
})

Router 使用 RootViewProvider 来查找哪个视图控制器是视图层次结构中的根视图控制器。 在 iOS 和 tvOS 上,RootViewProviderUIWindow 的接口,允许 Router 获取视图层次结构的根视图控制器。 但是,在其他平台以及应用程序扩展中,无法访问 UIApplication 共享窗口,在这种情况下,RootViewProvider 可能有所不同,例如,在 iMessage 应用程序中,MSMessagesAppViewController 可能扮演类似的角色。

ViewFinder 对象从根视图开始遍历视图层次结构,以查找当前在屏幕上可见的视图控制器。 在 iOS 和 tvOS 上,Ariadne 提供了 CurrentlyVisibleViewFinder 类的实现,该类递归搜索 UIViewControllerUINavigationControllerUITabBarController 以查找当前可见的视图控制器,但在其他平台和其他情况下,您可能希望使用您的实现或 CurrentlyVisibleViewFinder 的子类,如果您的视图层次结构包含其他视图控制器容器。

SwiftGen 集成

SwiftGen 是一个强大的代码生成器,可用于让您摆脱使用基于字符串的 API,这种 API 既繁琐又容易出错。 例如,对于故事板,SwiftGen 能够生成实例化视图控制器所需的代码,并使此代码在编译时保证故事板和视图控制器的存在。 Ariadne 可以在此基础上构建,从而为路由构建产生简洁的语法,如下所示

let route = Storyboards.User.userViewController.builder.embeddedInNavigation().presentRoute()

要了解如何实现这一点,请参阅 SwiftGen 集成 指南。

依赖注入

不同的应用程序可能具有完全不同的架构和要求。 要查看简单依赖注入的示例,请参阅 SwiftGen 集成,对于使用依赖容器(如 Dip)进行更高级的依赖注入,请转到 高级依赖注入示例 指南。

愿景

要了解有关项目未来目标和愿景的更多信息,请阅读 愿景 文档。

文档

您可以在这里找到完整的项目文档。

示例项目

iOS 示例项目可以在 Ariadne.xcodeproj 中找到,并且包含

许可

Ariadne 在 MIT 许可下发布。 有关更多信息,请参阅 LICENSE