FlowOperations 2.0

FlowOperations 2.0

测试已测试
语言语言 SwiftSwift
许可 MIT
发布最新发布2016 年 10 月
SPM支持 SPM

John Sundell 维护。



Flow

Flow 是一个轻量级的 Swift 库,用于面向操作编程。它允许您轻松定义自己的原子操作,并包含一个丰富的可重用操作库,这些操作可以分组、排序、排队和重复。

操作

使用 Flow 主要是将您的代码分解成多个原子部分,这些部分被称为 操作。每个操作定义了一个工作体,可以在应用程序或库中轻松重用。

操作可以执行任何同步或异步的操作,其范围完全由您决定。然而,操作驱动编程的真正力量在于您创建操作组、序列和队列。操作可以使代码变得更加简单,无论是异步操作还是需要在多个位置执行工作的情况。

如何使用

  • 通过在自定义对象中遵循 FlowOperation 创建自己的操作。所需做的只是实现一个带有完成处理程序的方法。它可以按照您希望的方式初始化,可以是 classstruct

  • 使用任何内置操作,例如 FlowClosureOperationFlowDelayOperation 等。

  • 使用 FlowOperationSequence 创建操作序列(按顺序执行),使用 FlowOperationGroup 创建组(同时执行),或使用 FlowOperationQueue 创建队列(可以连续添加操作)。

示例

假设我们正在开发一款游戏,并想要执行一系列动画,其中包括一个 Player 攻击一个 Enemy,摧毁它,然后播放胜利动画。当然,这可以通过使用完成处理程序闭包来完成

player.moveTo(enemy.position) {
    player.performAttack() {
        enemy.destroy() {
            player.playVictoryAnimation()
        }
    }
}

然而,这很快变得难以推理并调试,特别是当我们开始添加多个需要同步的动画时。假设我们决定在我们的游戏中实现一个新的 旋风攻击,它可以摧毁多个敌人,并且我们想在播放胜利动画之前摧毁所有敌人。我们将不得不这样做

player.moveTo(mainEnemy.position) {
    player.performAttack() {
        var enemiesDestroyed = 0

        for enemy in enemies {
            enemy.destroy({
                enemiesDestroyed += 1

                if enemiesDestroyed == enemies.count {
                    player.playVictoryAnimation()
                }
            })
        }
    }
}

显然,我们添加到动画中的内容越多,它就越容易出错,调试也越困难。如果我们能让动画(或任何其他任务序列)随着复杂性的增加而优雅地扩展,那岂不是很好?

让我们用流程来实现上述内容。我们首先定义在动画过程中需要执行的所有任务为 操作

/// Operation that moves a Player to a destination
class PlayerMoveOperation: FlowOperation {
    private let player: Player
    private let destination: CGPoint

    init(player: Player, destination: CGPoint) {
        self.player = player
        self.destination = destination
    }

    func perform(completionHandler: @escaping () -> Void) {
        self.player.moveTo(self.destination, completionHandler: completionHandler)
    }
}

/// Operation that performs a Player attack
class PlayerAttackOperation: FlowOperation {
    private let player: Player

    init(player: Player) {
        self.player = player
    }

    func perform(completionHandler: @escaping () -> Void) {
        self.player.performAttack(completionHandler)
    }
}

/// Operation that destroys an enemy
class EnemyDestroyOperation: FlowOperation {
    private let enemy: Enemy

    init(enemy: Enemy) {
        self.enemy = enemy
    }

    func perform(completionHandler: @escaping () -> Void) {
        self.enemy.destroy(completionHandler)
    }
}

/// Operation that plays a Player victory animation
class PlayerVictoryOperation: FlowOperation {
    private let player: Player

    init(player: Player) {
        self.player = player
    }

    func perform(completionHandler: @escaping () -> Void) {
        self.player.playVictoryAnimation()
        completionHandler()
    }
}

其次,我们将使用上述操作来实现我们的动画

let moveOperation = PlayerMoveOperation(player: player, destination: mainEnemy.position)
let attackOperation = PlayerAttackOperation(player: player)
let destroyEnemiesOperation = FlowOperationGroup(operations: enemies.map({
    return EnemyDestroyOperation(enemy: $0)
}))
let victoryOperation = PlayerVictoryOperation(player: player)

let operationSequence = FlowOperationSequence(operations: [
    moveOperation,
    attackOperation,
    destroyEnemiesOperation,
    victoryOperation
])

operationSequence.perform()

虽然使用操作需要写更多的代码;但这种方法有一些显著的优点。

首先;现在我们可以使用 FlowOperationGroup 来确保在继续之前所有敌人的动画都已完成,通过这种方式,我们已经减少了动画内部需要保持的状态。

其次;动画的各个部分现在都是独立的操作,不需要彼此知晓,这使得它们更容易测试和调试 - 并且也可以在我们游戏的其余部分中重用。

API参考

协议

FlowOperation 用来声明自定义操作。

FlowOperationCollection 用来声明自定义操作集合。

基本操作

FlowClosureOperation 运行闭包的操作,执行后直接返回。

FlowAsyncClosureOperation 运行闭包的操作,然后在闭包调用完成处理程序之前等待,才会结束。

FlowDelayOperation 在完成前等待一定延迟的操作。在序列和队列中很有用。

操作集合与实用工具

FlowOperationGroup 用于将一系列操作组合在一起,当该组执行时,同时执行这些操作。

FlowOperationSequence 用于编排一系列操作,顺序执行。

FlowOperationQueue 队列,空闲时立即执行下一个操作。新操作可以持续添加。

FlowOperationRepeater 用于重复操作,可以选择在重复之间使用间隔。

这与其他 NSOperations 有何不同?

NSOperations 是非常棒的,肯定是 Flow 的主要灵感之一。然而,NSOperations 比较重,可能需要很长时间来实现。Flow 设计来具有 NSOperations 的功能,但更易于使用。它也是100%使用 Swift 编写的,这使得它非常适合以 Swift 为基础的项⽬。

兼容性

Flow 支持 Apple 的所有当前平台,以下为最低版本要求:

  • iOS 8
  • macOS 10.11
  • watchOS 2
  • tvOS 9

Flow 的当前版本支持 Swift 3。如果您需要 Swift 2 支持,可以改用 版本 1.1,或使用 swift 2 分支

安装

CocoaPods

在您的 Podfile 中添加以下行 pod "FlowOperations"

Carthage

在您的 Cartfile 中添加以下行 github "johnsundell/flow"

手动

克隆存储库,并将文件 Flow.swift 拖入您的 Xcode 项目中。

Swift 包管理器

在您的 Package.swift 中添加以下行 .Package(url: "https://github.com/johnsundell/flow.git", majorVersion: 2)

希望您喜欢使用Flow!

如需支持、反馈以及有关Flow的新闻,请关注我的Twitter: @johnsundell