All Projects → JohnSundell → Flow

JohnSundell / Flow

Licence: mit
Operation Oriented Programming in Swift

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Flow

Ok ip proxy pool
🍿爬虫代理IP池(proxy pool) python🍟一个还ok的IP代理池
Stars: ✭ 196 (-8.84%)
Mutual labels:  async
Urf.net
Unit of Work & Repositories Framework - .NET 4.x
Stars: ✭ 202 (-6.05%)
Mutual labels:  async
Arsenic
Async WebDriver implementation for asyncio and asyncio-compatible frameworks
Stars: ✭ 209 (-2.79%)
Mutual labels:  async
Paper
Hassle-free HTML to PDF conversion abstraction library.
Stars: ✭ 196 (-8.84%)
Mutual labels:  async
Computed Types
🦩 Joi like validations for TypeScript
Stars: ✭ 197 (-8.37%)
Mutual labels:  async
Swoole Bundle
Symfony Swoole Bundle
Stars: ✭ 201 (-6.51%)
Mutual labels:  async
Fooproxy
稳健高效的评分制-针对性- IP代理池 + API服务,可以自己插入采集器进行代理IP的爬取,针对你的爬虫的一个或多个目标网站分别生成有效的IP代理数据库,支持MongoDB 4.0 使用 Python3.7(Scored IP proxy pool ,customise proxy data crawler can be added anytime)
Stars: ✭ 195 (-9.3%)
Mutual labels:  async
Crochet
Crochet: use Twisted anywhere!
Stars: ✭ 214 (-0.47%)
Mutual labels:  async
Evmongoose
DEPRECATED. Evmongoose is an asynchronous, event(libev) based multi-protocol embedded networking library with functions including TCP, HTTP, WebSocket, MQTT and much more. It's based on mongoose and libev implementation and it's support Lua API.
Stars: ✭ 199 (-7.44%)
Mutual labels:  async
Byte Stream
A non-blocking stream abstraction for PHP based on Amp.
Stars: ✭ 208 (-3.26%)
Mutual labels:  async
Slack Client
A better Slack client, with RTM API support.
Stars: ✭ 196 (-8.84%)
Mutual labels:  async
Liquidstate
Efficient asynchronous and synchronous state machines for .NET
Stars: ✭ 197 (-8.37%)
Mutual labels:  async
Asyncfriendlystacktrace
Async-friendly format for stack traces and exceptions
Stars: ✭ 205 (-4.65%)
Mutual labels:  async
Gmqtt
Python MQTT v5.0 async client
Stars: ✭ 195 (-9.3%)
Mutual labels:  async
Modern Apis With Fastapi
Course demos and handouts for our Modern APIs with FastAPI course.
Stars: ✭ 212 (-1.4%)
Mutual labels:  async
Trilogy
TypeScript SQLite layer with support for both native C++ & pure JavaScript drivers.
Stars: ✭ 195 (-9.3%)
Mutual labels:  async
Fastapi Gino Arq Uvicorn
High-performance Async REST API, in Python. FastAPI + GINO + Arq + Uvicorn (w/ Redis and PostgreSQL).
Stars: ✭ 204 (-5.12%)
Mutual labels:  async
Aioreactive
Async/await reactive tools for Python 3.9+
Stars: ✭ 215 (+0%)
Mutual labels:  async
Tickedoff
Tiny library (<200B gzip) for deferring something by a "tick"
Stars: ✭ 213 (-0.93%)
Mutual labels:  async
Async Tungstenite
Async binding for Tungstenite, the Lightweight stream-based WebSocket implementation
Stars: ✭ 207 (-3.72%)
Mutual labels:  async

Flow

Travis CocoaPods Carthage

Flow is a lightweight Swift library for doing operation oriented programming. It enables you to easily define your own, atomic operations, and also contains an exensive library of ready-to-use operations that can be grouped, sequenced, queued and repeated.

Operations

Using Flow is all about splitting your code up into multiple atomic pieces - called operations. Each operation defines a body of work, that can easily be reused throughout an app or library.

An operation can do anything, synchronously or asynchronously, and its scope is really up to you. The true power of operation oriented programming however, comes when you create groups, sequences and queues out of operations. Operations can potentially make code that is either asynchronous, or where work has to be done in several places, a lot simpler.

How to use

  • Create your own operations by conforming to FlowOperation in a custom object. All it needs to do it implement one method that performs it with a completion handler. It’s free to be initialized in whatever way you want, and can be either a class or a struct.

  • Use any of the built-in operations, such as FlowClosureOperation, FlowDelayOperation, etc.

  • Create sequences of operations (that get executed one by one) using FlowOperationSequence, groups (that get executed all at once) using FlowOperationGroup, or queues (that can be continuously filled with operations) using FlowOperationQueue.

Example

Let’s say we’re building a game and we want to perform a series of animations where a Player attacks an Enemy, destroys it and then plays a victory animation. This could of course be accomplished with the use of completion handler closures:

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

However, this quickly becomes hard to reason about and debug, especially if we start adding multiple animations that we want to sync. Let’s say we decide to implement a new spin attack in our game, that destroys multiple enemies, and we want all enemies to be destroyed before we play the victory animation. We’d have to do something like this:

player.moveTo(mainEnemy.position) {
    player.performAttack() {
        var enemiesDestroyed = 0
                
        for enemy in enemies {
            enemy.destroy({
                enemiesDestroyed += 1
                        
                if enemiesDestroyed == enemies.count {
                    player.playVictoryAnimation()
                }
            })
        }
    }
}

It becomes clear that the more we add to our animation, the more error prone and hard to debug it becomes. Wouldn’t it be great if our animations (or any other sequence of tasks) could scale gracefully as we make them more and more complex?

Let’s implement the above using Flow instead. We’ll start by defining all tasks that we need to perform during our animation as operations:

/// 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()
    }
}

Secondly; we’ll implement our animation using the above operations:

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()

While we had to write a bit more code using operations; this approach has some big advantages.

Firstly; we can now use a FlowOperationGroup to make sure that all enemy animations are finished before moving on, and by doing this we’ve reduced the state we need to keep within the animation itself.

Secondly; all parts of the animation are now independant operations that don’t have to be aware of each other, making them a lot easier to test & debug - and they could also be reused in other parts of our game.

API reference

Protocols

FlowOperation Used to declare custom operations.

FlowOperationCollection Used to declare custom collections of operations.

Base operations

FlowClosureOperation Operation that runs a closure, and returns directly when performed.

FlowAsyncClosureOperation Operation that runs a closure, then waits for that closure to call a completion handler before it finishes.

FlowDelayOperation Operation that waits for a certain delay before finishing. Useful in sequences and queues.

Operation collections & utilities

FlowOperationGroup Used to group together a series of operations that all get performed at once when the group is performed.

FlowOperationSequence Used to sequence a series of operations, performing them one by one once the sequence is performed.

FlowOperationQueue Queue that keeps executing the next operation as soon as it becomes idle. New operations can constantly be added.

FlowOperationRepeater Used to repeat operations, optionally using an interval in between repeats.

How is this different from NSOperations?

NSOperations are awesome - and are definetly one of the main sources of inspiration for Flow. However, NSOperations are quite heavyweight and can potentially take a long time to implement. Flow was designed to have the power of NSOperations, but be a lot easier to use. It’s also written 100% using Swift - making it ideal for Swift-based projects.

Compatibility

Flow supports all current Apple platforms with the following minimum versions:

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

The current version of Flow supports Swift 3. If you need Swift 2 support, either use version 1.1, or the swift 2 branch.

Installation

CocoaPods:

Add the line pod "FlowOperations" to your Podfile

Carthage:

Add the line github "johnsundell/flow" to your Cartfile

Manual:

Clone the repo and drag the file Flow.swift into your Xcode project.

Swift Package Manager:

Add the line .Package(url: "https://github.com/johnsundell/flow.git", majorVersion: 2) to your Package.swift

Hope you enjoy using Flow!

For support, feedback & news about Flow; follow me on Twitter: @johnsundell.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].