Skip to content

Instantly share code, notes, and snippets.

@feighter09
Last active May 18, 2017 08:51
Show Gist options
  • Save feighter09/0a1af792344782ff5d3f to your computer and use it in GitHub Desktop.
Save feighter09/0a1af792344782ff5d3f to your computer and use it in GitHub Desktop.
Functional View Controllers from Chris Eidhof's talk @ FunSwiftConf 2015
import UIKit
// MARK: - Building Blocks
struct Screen<A> {
let run: (A -> Void) -> UIViewController
}
extension Screen {
func map<B>(f: A -> B) -> Screen<B>
{
return Screen<B> { onComplete in
return self.run { a in
onComplete(f(a))
}
}
}
}
struct Flow<A> {
let build: (naviagationController: UINavigationController, onComplete: A -> Void) -> UIViewController
private init(build: (naviagationController: UINavigationController, onComplete: A -> Void) -> UIViewController)
{
self.build = build
}
}
extension Flow {
init(screen: Screen<A>)
{
build = { nav, onComplete in
let vc = screen.run(onComplete)
nav.pushViewController(vc, animated: true)
return nav
}
}
func run(navigationController: UINavigationController = UINavigationController(),
onComplete: A -> Void = { _ in }) -> UIViewController
{
build(naviagationController: navigationController, onComplete: onComplete)
return navigationController
}
func flatMap<B>(f: A -> Flow<B>) -> Flow<B>
{
return Flow<B>(build: { (navigationController, onComplete) -> UIViewController in
return self.build(naviagationController: navigationController, onComplete: { a in
f(a).build(naviagationController: navigationController, onComplete: onComplete)
})
})
}
func push<B>(f: A -> Screen<B>) -> Flow<B>
{
return flatMap { a in Flow<B>(screen: f(a)) }
}
}
// MARK: - Use
infix operator >>> { associativity left }
func >>> <A, B>(flow: Flow<A>, f: A -> Screen<B>) -> Flow<B>
{
return flow.push(f)
}
func >>> <A, B>(flow: Flow<A>, f: A -> Flow<B>) -> Flow<B>
{
return flow.flatMap(f)
}
protocol Screenable {
typealias A
typealias B
static func screen(initData: A) -> Screen<B>
init(initData: A, onComplete: B -> Void)
var onComplete: B -> Void { get }
}
extension Screenable {
static func screen(initData: Self.A) -> Screen<B>
{
return Screen<B> { onComplete in
Self(initData: initData, onComplete: onComplete) as! UIViewController
}
}
}
extension Screenable where A == Void {
static func screen() -> Screen<B>
{
return Screen<B> { onComplete in
Self(initData: Void(), onComplete: onComplete) as! UIViewController
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment