Ariadne 0.7.0

Ariadne 0.7.0

Denys Telezhkin 维护。



Ariadne 0.7.0

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

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

需求

  • iOS 10+
  • macOS 10.12+
  • tvOS 10+
  • watchOS 3+
  • Xcode 10 / Swift 4.2 及以上版本

安装

Swift Package Manager(需要 Xcode 11)

  • 在“项目设置”中添加软件包 -> “Swift 软件包”

CocoaPods

pod 'Ariadne'

概述

Ariadne 架构本质上是始于 ViewBuilder。由于在 iOS 上视图控制器与其视图紧密耦合,因此 UIViewController 被视为视图,并重命名为 ViewController

注意:在 watchOS 上,ViewControllerWKInterfaceController 的同义词,macOS 上是 NSViewController,原因类似。

ViewBuilder 的定义很简单——它从提供的 Context 构建一个视图控制器

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

无需额外的设置,Ariadne 提供了以下构建器:

  • UINavigationController
  • UITabBarController
  • UISplitViewController

框架的第二个构建块是 ViewTransition 对象,用于在视图间执行转换。以下是支持的以下转换:

  • UINavigationController 转换 - push、pop、pop 到根控制器、pop 到视图控制器、替换导航堆栈中的控制器
  • UIViewController 展示 - present、dismiss
  • UIWindow 根视图控制器转换以通过动画进行根视图控制器的切换。

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

let alertRoute = AlertBuilder().presentRoute()

注意在 AlertBuilder 和任何 UIViewController 构建器上都是如何调用相同的 presentRoute 方法。通过利用 ViewBuilder 协议的扩展,任何转换和路由都可以在 ViewBuilder 实例中重复使用。要了解 ViewBuilder 协议的实现和扩展的示例,请参阅 实现视图构建器 指南。

最后但同样重要的是,Router 对象将一切结合起来,并允许您实际执行路由

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

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

ViewFinder 对象从根视图开始遍历视图层次结构,以找到当前屏幕上可见的视图控制器。在 iOS 和 tvOS 上,Ariadne 提供了 CurrentlyVisibleViewFinder 类的实现,该类递归搜索 UIViewControllerUINavigationControllerUITabBarController 以找到当前可见的视图控制器,但在其他平台和其他场景中,您可能需要实现自己的或 CurrentlyVisibleViewFinder 的子类实现,如果您的视图层次结构包含其他视图控制器容器。

SwiftGen 集成

SwiftGen 是一个强大的代码生成器,它可以用来让您摆脱使用基于 String 的 API,这些 API 繁琐且易于出错。例如,使用 storyboards,SwiftGen 可以生成生成视图控制器的代码,并保证在编译时视图控制器和 storyboard 存在。Ariadne 可以在此基础上构建,生成构建路由的整洁语法,如下所示

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

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

依赖注入

不同的应用程序可能具有完全不同的架构和需求。要查看简单依赖注入的示例,请参阅 实现视图构建器 指南,对于更高级的依赖注入(如使用依赖容器 Dip),请参阅 高级依赖注入示例 指南。

愿景

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

文档

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

示例项目

Ariadne.xcodeproj中的iOS示例项目包含

  • 根视图控制器动画切换
  • 推送/弹出,显示/隐藏
  • 预览 & 弹出
  • 自定义过渡和显示
  • 更新当前视图。

许可证

Ariadne遵照MIT许可证发布。有关更多信息请见许可证