使用Elm构建iOS应用程序
使用Elm构建iOS应用程序。 使用本机或Web UI。 或混合搭配
Swift 其它杂项
共185Star
详细介绍
Elm for iOS
Build iOS apps with Elm. Use native or web UI. Or mix and match.
Continuous integration status:
master |
develop |
---|---|
Example
Let's build a counter:
Functional core
- 100% platform independent
- 100% type safe
- 100% purely functional
port module Counter exposing (..)
type alias Model =
Int
model : Model
model =
0
type alias Flags =
{ initialCount : Int }
init : Flags -> ( Model, Cmd Msg )
init flags =
let
initialModel =
flags.initialCount
in
( initialModel, view initialModel )
type Msg
= Increment
| Decrement
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
let
newModel =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
command =
view newModel
in
( newModel, command )
type alias View =
{ count : String }
view : Model -> Cmd Msg
view model =
setCountLabelText (toString model)
port userDidTapIncrementButton : (() -> msg) -> Sub msg
port userDidTapDecrementButton : (() -> msg) -> Sub msg
port setCountLabelText : String -> Cmd msg
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.batch
[ userDidTapIncrementButton (\_ -> Increment)
, userDidTapDecrementButton (\_ -> Decrement)
]
main : Program Flags Model Msg
main =
Platform.programWithFlags
{ init = init
, update = update
, subscriptions = subscriptions
}
Tests:
module Tests exposing (..)
import Test exposing (..)
import Expect
import Counter exposing (..)
model : ( Model, Cmd Msg ) -> Model
model =
Tuple.first
command : ( Model, Cmd Msg ) -> Cmd Msg
command =
Tuple.second
all : Test
all =
describe "Update"
[ describe "Increment"
[ test "Change model 1" <|
\() ->
update Increment 1
|> model
|> Expect.equal 2
, test "Change model 2" <|
\() ->
update Increment 2
|> model
|> Expect.equal 3
, test "Send command 1" <|
\() ->
update Increment 1
|> command
|> Expect.equal (setCountLabelText "2")
, test "Send command 2" <|
\() ->
update Increment 2
|> command
|> Expect.equal (setCountLabelText "3")
]
, describe "Decrement"
[ test "Change model 1" <|
\() ->
update Decrement -1
|> model
|> Expect.equal -2
, test "Change model 2" <|
\() ->
update Decrement -2
|> model
|> Expect.equal -3
, test "Send command 1" <|
\() ->
update Decrement -1
|> command
|> Expect.equal (setCountLabelText "-2")
, test "Send command 2" <|
\() ->
update Decrement -2
|> command
|> Expect.equal (setCountLabelText "-3")
]
]
Imperative shell
- Platform dependent
- Divided into two parts — safe and unsafe
Safe part:
import UIKit
import Elm
final class ViewController: UIViewController, Elm {
@IBOutlet var countLabel: UILabel?
struct Flags {
let initialCount: Int
}
enum Input {
case userDidTapIncrementButton
case userDidTapDecrementButton
}
enum Output {
case setCountLabelText(String)
}
override func viewDidLoad() {
super.viewDidLoad()
start(module: "counter", flags: .init(initialCount: 0))
}
@IBAction func userDidTapIncrementButton() {
send(.userDidTapIncrementButton)
}
@IBAction func userDidTapDecrementButton() {
send(.userDidTapDecrementButton)
}
func observe(_ output: Output) {
switch output {
case .setCountLabelText(let text):
countLabel?.text = text
}
}
}
Unsafe part where we convert data between Swift to JavaScript:
extension ViewController.Flags: ElmValue {
var javaScript: String {
return ["initialCount": initialCount].javaScript
}
}
extension ViewController.Input: ElmInput {
var port: (ElmPort, ElmValue?) {
switch self {
case .userDidTapIncrementButton:
return ("userDidTapIncrementButton", nil)
case .userDidTapDecrementButton:
return ("userDidTapDecrementButton", nil)
}
}
}
extension ViewController.Output: ElmOutput {
init(port: ElmPort, value: ElmValue) {
switch port {
case "setCountLabelText":
let value = value as! String
self = .setCountLabelText(value)
default:
fatalError()
}
}
}
Build
Add the following Run Script build phase to compile Elm during Xcode build:
elm make "$SRCROOT"/Elm/src/Counter.elm --output "$CONFIGURATION_BUILD_DIR"/"$UNLOCALIZED_RESOURCES_FOLDER_PATH"/counter.js --yes
Notes
Due to this bug, all port
modules need to include:
import Json.Decode
Thanks
Questions? Comments? Concerns?
-
41 Star
-
289 Star
-
239 Star
-
193 Star
-
863 Star
-
8836 Star
-
2831 Star
-
497 Star