Examples

Basic Demo

This example is shipped as part of the repo inside FlaskSamples.

FlaskManifest.swift

import UIKit
import Flask

//Mark: - Global Reactive Substance Mixers

enum EnvMixers : SubstanceMixer {
    case Login
    case Logout
    case AsyncAction
}

enum NavMixers : SubstanceMixer {
    case Home
    case Settings
}

class Subs {

    static let app = AppSubstance()
    static let appReactive = AppReactiveSubstance()
}

AppSubstance.swift

import UIKit
import Flask

//Mark: - A sample State definition

struct AppState : State {

    enum prop : StateProp{
        case counter, title, asyncResult
    }

    var counter = 0
    var title = ""
    var asyncResult = ""
    var object:FlaskNSRef?
    var map:FlaskDictRef?

    var _internal = "`_` use this prefix for internal vars "

}

//Mark: - A sample Reactive Substance

class AppReactiveSubstance : ReactiveSubstance<AppState,EnvMixers> {

    override func defineMixers(){

        define(mix: .Login) { (payload, react, abort)  in
            self.prop.title = "signed"
            react()
        }

        define(mix: .Logout) { (payload, react, abort)  in
           self.prop.title = "not signedd"
            react()
        }

        define(mix: .AsyncAction){ (payload, react, abort)  in
            self.prop.asyncResult = "async action pending"
            react()
        }

        define(mix: NavMixers.Home) { (payload, react, abort)  in

            abort()
        }

        define(mix: NavMixers.Settings) { (payload, react, abort)  in
            //TODO
            abort()
        }
    }

}

//Mark: - A sample Substance

class AppSubstance : Substance<AppState> {}

ViewController.swift

import UIKit
import Flask

class ViewController: UIViewController, FlaskReactor  {

    //Mark: an inline Substance
    let substance = Flask.newSubstance(definedBy: AppState.self)

    func flaskReactions(reaction: FlaskReaction) {

        //using the state enums
        reaction
            .at(substance)?
            .on(AppState.prop.counter) { (change) in
                print("local substance counter = \(substance.state.counter)")
        }


        //using prop as string
        reaction
            .at(Subs.appReactive)?
            .on("counter") { (change) in
                print("global substance counter = \(Subs.appReactive.state.counter)")
        }


        // if no name conflicts the .at(store) may be skipped
        reaction.on(AppState.prop.title) { (change) in
            print("global title = \(Subs.appReactive.state.title)")
        }

        reaction.on(AppState.prop.asyncResult) { (change) in
            print("global title = \(Subs.appReactive.state.asyncResult)")

            DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                //release when the operation is completed
                reaction.onLock?.release()
            });
        }



    }

    override func viewDidLoad() {

        Flask.attachReactor(to:self, mixing:[substance, Subs.appReactive])
        produceTestReaction()
    }


    func produceTestReaction(){

        //dipose saved state between sessions for testing
        substance.shouldArchive = false


        Flask.substances(reactTo: EnvMixers.Login)

        Flask.getReactor(attachedTo:self)
            .mixing(self.substance) { (substance) in

                //local substance
                substance.prop.counter = 10

            }.with(Subs.appReactive) { (substance) in

                //global substance
                substance.prop.counter = 1000

            }.andReact()

        // a simple lock
        let lock = Flask.lock()

        // perform operations while the flux is paused
        // then release
        lock.release()

        // a mixer lock, blocks the normal flux
        // an immediately performs this mixer
        Flask.lock(withMixer: EnvMixers.AsyncAction)

        // logout won't be performed until the above lock is released (see handler code)
        Flask.substances(reactTo: EnvMixers.Logout)
    }   
}