Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SwiftUI with TCA in LINE LIVE Commerce Assistant App @ TECHPULSE 2023

SwiftUI with TCA in LINE LIVE Commerce Assistant App @ TECHPULSE 2023

- Speaker: Jason Liang
- Event: http://techpulse.line.me/

隨著電商直播的需求越來越高,因此今年上半年將推出 LINE Live Commerce Assistant App,讓直播主能夠更快速地開啟直播。本次議程將透過 swiftUI 與 TCA,帶大家走訪在 App 開發時所會遇到的各種眉角,了解框架與測試所帶來的好處。

LINE Developers Taiwan
PRO

February 21, 2023
Tweet

More Decks by LINE Developers Taiwan

Other Decks in Technology

Transcript

  1. View Slide

  2. Agenda
    › LINE Live Commerce Assistant App
    › High concurrent auction chat room
    › New UI framework and architecture and why
    › SwiftUI
    › The Composable Architecture (TCA)
    › Challenge we met
    2

    View Slide

  3. LINE Live Commerce Assistant App
    Creating a live streaming was not that easy
    Hardware
    Camera
    Software
    Streaming
    Website
    CMS
    3

    View Slide

  4. KOREA
    COLOMBIA
    MEXICO
    LINE Live Commerce Assistant App
    Available in this year
    SINGAPORE
    THAILAND
    MALAYSIA
    THE UNITED STATES
    INDONESIA
    JAPAN
    TAIWAN
    SPAIN TURKEY
    4

    View Slide

  5. LINE LIVE Commerce Assistant App
    5
    An app that allows streamers to create and stream at one place

    View Slide

  6. Why SwiftUI
    Is it really ready for business application?
    Efficiency
    Less Code
    Readability
    Declarative
    Programming
    Hot Reload
    Previews
    6

    View Slide

  7. ScrollView {
    LazyVStack(spacing: 0) {
    ForEach(
    viewStore.messages, id: \.id
    ) { message in
    MessageView(message: message)
    }
    ...
    }
    ...
    }
    Better Apps. Less Code
    7

    View Slide

  8. Why SwiftUI
    Readable code and easy to verify UI via Xcode Previews
    struct LiveStopwatchView_Previews: PreviewProvider {
    private static var startTime = Date()
    private static var elapsedSeconds: TimeInterval = 31_233
    @ViewBuilder
    static func staticTimeInterval(
    _ elapsedSeconds: TimeInterval
    ) -> some View {
    Text("\(elapsedSeconds, format: .number) seconds")
    LiveStopwatchView(...)
    }
    static var previews: some View {
    VStack {
    Grid {
    GridRow { staticTimeInterval(10_342) }
    GridRow { staticTimeInterval(359_999) }
    GridRow { staticTimeInterval(360_000) }
    }
    }
    .padding(40)
    .previewLayout(.sizeThatFits)
    }
    }
    8

    View Slide

  9. Why The Composable Architecture (TCA)
    Building apps in a consistent and understandable way, with composition, testing, and ergonomics in mind
    Independent
    State
    SwiftUI Style
    Dependency
    Prioritized
    Testability
    9

    View Slide

  10. The Composable Architecture (TCA)
    The app is composed of state of independent features
    10
    Root
    Login
    Home
    Broadcast
    Settings

    View Slide

  11. The Composable Architecture (TCA)
    The app is composed of state of independent features
    11
    Root
    Login
    Home
    Broadcast
    Settings

    View Slide

  12. ViewStore
    The Composable Architecture (TCA)
    The flow of an independent composable feature (scope)
    12
    Reducer
    State
    Action
    StoreOf
    LoginView
    Dependencie

    View Slide

  13. The Composable Architecture (TCA)
    ReducerProtocol
    13
    Reducer
    State
    Action
    StoreOf struct Login: ReducerProtocol {
    struct State: Equatable {
    var isLoading = false
    }
    enum Action {
    case loginButtonTapped
    }
    var body: some ReducerProtocolOf {
    Reduce { state, action in
    switch action {
    case .loginButtonTapped
    state.isLoading = true
    return .task {
    // login
    }
    }
    }
    }
    }

    View Slide

  14. The Composable Architecture (TCA)
    Dependency Injection
    14
    Reducer
    State
    Action
    StoreOf struct Login: ReducerProtocol {
    @Dependency(\.authManager) var authManager
    enum Action {
    ...
    case loginResponse(TaskResult)
    }
    var body: some ReducerProtocolOf {
    Reduce { state, action in
    switch action {
    case .loginButtonTapped:
    state.isLoading = true
    return .task {
    .loginResponse(
    TaskResult(await authManager.login())
    )
    }
    case .loginResponse(let result):
    // handle result
    }
    }
    }
    }
    Dependencie

    View Slide

  15. The Composable Architecture (TCA)
    Communication between View and Store
    15
    struct LoginView: View {
    let store: StoreOf
    @ObservedObject
    var viewStore: ViewStoreOf
    var body: some View {
    // ...
    VStack {
    Button("Login") {
    viewStore.send(.loginButtonTapped)
    }
    .disabled(viewStore.isLoading)
    }
    }
    }
    ViewStore
    Reducer
    State
    Action
    StoreOf
    LoginView

    View Slide

  16. The Composable Architecture (TCA)
    Testing
    16
    func testLoginButtonTapped() async throws {
    let store = TestStore(
    initialState: Login.State(isLoading: false),
    reducer: Login()
    )
    await store.send(.loginButtonTapped, assert: {
    $0.isLoading = true
    })
    }
    struct LoginView: View {
    let store: StoreOf
    @ObservedObject
    var viewStore: ViewStoreOf
    var body: some View {
    // ...
    VStack {
    Button("Login") {
    viewStore.send(.loginButtonTapped)
    }
    .disabled(viewStore.isLoading)
    }
    }
    }

    View Slide

  17. The Composable Architecture (TCA)
    Easy to find the non-matched changes from log
    17
    func testLoginButtonTapped() async throws {
    let store = TestStore(
    initialState: Login.State(isLoading: false),
    reducer: Login()
    )
    await store.send(.loginButtonTapped, assert: {
    $0.isLoading = true
    })
    }
    testLoginButtonTapped(): A state change does not match expectation: ...
    − Login.State(isLoading: false)
    + Login.State(isLoading: true)
    (Expected: −, Actual: +)

    View Slide

  18. Challenge we met
    18

    View Slide

  19. Challenge We Met
    It’s really good enough, but we do encounter a few challenges
    › Content offset, if edges get reached and is scrolling
    › Keyboard presentation/dismissal
    Scrolling observation
    Behavior may vary according to iOS version
    › Extra testing effort
    Communication between imperative and declarative programming
    › UI components made for UIKit
    › e.g. WKWebView
    19

    View Slide

  20. Thank you
    20

    View Slide