Lasso 1.6.0

Lasso 1.6.0

Steven GrosmarkSteven GrosmarkSteven Grosmark维护。



Lasso 1.6.0

  • Steven Grosmark 和 Trevor Beasty

Lasso logo

Lasso 是一种用于构建离散、可组合和可测试组件的 iOS 应用架构,无论大小,从单个一次性屏幕到复杂流程,再到高级应用程序结构。

为什么选择 Lasso?

没有一组结构原则,应用程序的代码库很难进行推理和维护。特别是,以下问题最终会出现:

  • 组件之间的紧密耦合使得更改/测试东西变得困难
  • 业务逻辑存在于奇怪的地方,使得修改/重用/调试/测试现有代码变得困难
  • 视图呈现选择的地点不合适,使得重构/重新组织/测试流程变得困难
  • 团队之间的组织不一致,使得跨贡献变得困难

Lasso 方式

Lasso 通过明确定义离散的、单一职责组件以及这些组件之间通信的清晰、灵活方式,鼓励强烈的关注点分离。更大的行为单元可以轻松组合,并可以重新组合。

屏幕

我们通常认为屏幕是一个应用中的单个页面/视图,例如,登录视图、联系人列表视图、音频设置视图等。

在Lasso中,Screen是一系列类型集合,用于实现单个视图。

Diagram of a Screen and its constituent parts

View(即UIViewController)负责:

  • 准确渲染屏幕当前State(即内容)
  • 将用户交互传递给Store(即决策者)
  • 响应状态变化以保持展示的实时性

Lasso视图通常很小,其中几乎不含逻辑。

使用单向数据流确保一致性:视图从不会直接响应用户操作而重新渲染任何内容。ViewStore发送ActionsStore更新State,然后作为状态变更通知返回给View

Store是屏幕决策的地方,并且是屏幕State的真理之源。一个Store负责:

  • 屏幕所有业务逻辑
  • 响应Actions(即从View发送的事件)
  • 屏幕State的更新

在发生更适合其他地方处理的事件时,Store也可以生成一个Output。例如,登录屏幕可能会生成一个“用户已登录”的输出,作为向高级系统移动到应用登录部分的一个信号;或者联系人列表屏幕可能会生成一个“选择联系人”的输出,作为向高级流程显示或推送联系人详情屏幕的信号。

流程

Flow代表一个功能——或区域——的应用,通常由一系列Screen组成。例如,“新用户”流程可能由一系列一次性信息屏幕和一个单独的“开始使用”屏幕组成。

Diagram of a Flow

Flow在视图层次结构适当的上下文中创建和启动(例如,“注册”流程可能在一个菜单屏幕上呈现,或者“欢迎”流程可能被推送到导航堆栈)。Flow启动时会创建它的初始Screen,并监听Output信号。随着Outputs的到来,Flow决定如何处理它们——它可以创建并在视图层次结构中放置另一个Screen,发出它自己的Output(当发生更适合其他地方处理的事件时),或者对Flow来说是适当的事情。

由于ScreenFlow都被封装成具有离散的进入和退出门户的模块,因此一个Flow管理ScreenFlow都是非常简单和常见的。这样,就可能在组件层次结构中将应用定义为一个结构,从顶层到底层减少复杂性。

Diagram of a Flow within another Flow

示例应用

运行示例项目

  1. 克隆 Lasso 仓库
  2. Example 目录下运行 pod install
  3. 打开 Lasso.xcworkspace

了解更多

需求

Lasso 支持 iOS 13 及以上版本,并可以使用 Swift 4.2 及以上版本 进行编译。

注意:Lasso v.1.3.0 添加了对 SwiftUI 的支持,并且具有 iOS 13.0 的最低部署目标。如果需要支持更早的 iOS 版本,请使用 v1.2.1。

安装

Cocoapods

将Lasso核心框架添加到Podfile中的主目标

Pod 'Lasso'

同时将LassoTestUtilities添加到您的测试目标

Pod 'LassoTestUtilities'

Swift Package Manager

Lasso包的URL为

`https://github.com/ww-tech/lasso.git`

关于示例用法,请参阅: Swift Package Manager 示例

Tuist

要将Lasso添加为tuistTargetDependency

  • 将此仓库克隆到您首选的位置
  • 创建一个.project依赖项
  • 将依赖项添加到您的目标依赖项中
let lasso: TargetDependency = .project(target: "Lasso", path: "../../path-to-lasso-repo-clone/")

let demo = Target(
    name: "Demo",
    platform: .iOS,
    product: .framework,
    bundleId: "com.example.Demo",
    dependencies: [ lasso ]
)

同时将LassoTestUtilities添加到您的测试目标

let lassoTestUtilities: TargetDependency = .project(target: "LassoTestUtilities", path: "../../path-to-lasso-repo-clone/")

let demoTests = Target(
    name: "DemoTests",
    platform: .iOS,
    product: .unitTests,
    bundleId: "com.example.DemoTests",
    dependencies: [ LassoTestUtilities ]
)

贡献

我们热爱贡献!

如果您有新功能的想法,或者发现了bug,最好的做法是

  1. 搜索问题,看看是否有人已经提出过!
  2. 创建一个新问题,详细说明您希望看到哪些改进。
  3. 如果您有代码更改的想法,那就太棒了!
    1. Fork Lasso仓库
    2. 为您的功能更改创建一个分支
    3. 开启一个PR!

作者

Steven GrosmarkTrevor Beasty,Yuichi Kuroda,以及WW iOS团队。

许可证

Lasso遵循Apache-2.0开源许可证

您可以自由使用它。我们欢迎您给予归功(致谢),如果您在使用项目中使用它,我们非常乐意听到您的反馈!