Created
August 3, 2018 17:27
-
-
Save gfontenot/2d6c2b66035c872a005c07e7b4622cae to your computer and use it in GitHub Desktop.
Quick spike on an elm-ish architecture in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Dumb value types representing UIViews. Comperable to our current models like Button.Model | |
struct StackView<Message> { | |
let children: [View<Message>] | |
} | |
struct Label { | |
let text: String | |
} | |
struct Space { | |
let width: Int | |
} | |
struct TextField<Message> { | |
let text: String | |
} | |
// Generic type representing all available views. Cases aren't intended to be used directly | |
enum View<Message> { | |
case _stackView(StackView<Message>) | |
case _label(Label) | |
case _space(Space) | |
case _textField(TextField<Message>) | |
} | |
// Static functions for creating View instances. Takes any info needed and passes it through to the associated value | |
extension View { | |
static func stackView(_ children: [View<Message>]) -> View { | |
return ._stackView(StackView(children: children)) | |
} | |
static func label(_ text: String) -> View { | |
return ._label(Label(text: text)) | |
} | |
static func space(width: Int) -> View { | |
return ._space(Space(width: width)) | |
} | |
static func textField(text: String) -> View { | |
return ._textField(TextField(text: text)) | |
} | |
} | |
// A high level representation of a single component. Comperable to our current Presenter protocols | |
protocol Component { | |
// The state that the component cares about. | |
associatedtype Model | |
// Actions that can result in the state changing. | |
associatedtype Message | |
// Given a model, use this view heirarchy | |
static func view(_ model: Model) -> View<Message> | |
// Given a model and a message, return an updated model | |
static func update(_ model: Model, _ message: Message) -> Model | |
} | |
// A concrete representation of a single component, comperable to our current Presenter/ViewModel implementations | |
struct Calculator: Component { | |
struct Model { | |
let current: Int | |
} | |
enum Message { | |
case add(Int) | |
case subtract(Int) | |
} | |
static func view(_ model: Calculator.Model) -> View<Calculator.Message> { | |
return .stackView([ | |
.stackView([ | |
.label("Current Value"), | |
.label("\(model.current)"), | |
nameView("Gordon") | |
]) | |
]) | |
} | |
static func update(_ model: Calculator.Model, _ message: Calculator.Message) -> Calculator.Model { | |
switch message { | |
case let .add(n): return Model(current: model.current + n) | |
case let .subtract(n): return Model(current: model.current - n) | |
} | |
} | |
// An example of an extracted helper function for creating a smaller piece of the overall view. | |
private static func nameView(_ name: String) -> View<Message> { | |
return .stackView([ | |
.label("Name"), | |
.space(width: 10), | |
.textField(text: name) | |
]) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment