[SwiftUI] 아키텍처 고민

2024. 1. 6. 15:59·Swift/정리
728x90

아키텍처

Toucher 개발을 리펙토링 하면서 제일 먼저 한 고민은 "어떤 아키텍처를 해야하는 것인가,,?" 이었습니다. 

일단 저희한테 맞는 아키텍처를 찾으려면 어떠한 아키텍처가 SwiftUI 에서 사용이 되는지 알아봤어야 했기에 간단하게 서치를 해봤습니다.

MVC

Model-View-Controller

주로 UIkit에서 이용을 합니다.

SwiftUI에서는 아래와 같은 이유로 사용을 지양하고 있습니다.

  1. SwiftUI는 선언적인 구문을 사용하여 UI를 정의합니다. 원하는 결과를 선언하고 프레임워크가 알아서 상태 및 레이아웃을 관리합니다.
  2. SwiftUI는 바인딩(Binding) 및 상태 속성(State Property)과 같은 반응형 프로그래밍 개념을 도입하여 UI 요소를 데이터에 쉽게 바인딩할 수 있습니다.
  3. MVVM은 단일 소스 오브 트루스 원칙을 강조합니다. 즉, 데이터의 상태는 하나의 ViewModel에 집중되며, 이 상태에 따라 UI가 업데이트됩니다.

Model (모델):

  • 데이터와 데이터의 처리를 담당합니다.
  • 애플리케이션의 비즈니스 로직, 데이터 관리, 상태 정보 등을 처리합니다.
class CalculatorModel {
    var result: Double = 0.0

    func add(_ number: Double) {
        result += number
    }

    func subtract(_ number: Double) {
        result -= number
    }

    // 다른 계산 메서드들...
}

View (뷰):

  • 사용자 인터페이스를 담당합니다.
  • 모델에서 전달된 데이터를 표시하고, 사용자 입력을 받아 컨트롤러에 전달합니다.
import UIKit

class CalculatorView: UIView {
    let resultLabel = UILabel()

    // 뷰 구성 및 레이아웃 설정 등의 메서드들...
}

Controller (컨트롤러):

  • 모델과 뷰를 연결하고 제어합니다.
  • 사용자 입력을 받아 모델에 전달하고, 모델의 변경사항을 뷰에 반영합니다.
class CalculatorController {
    let calculatorModel = CalculatorModel()
    let calculatorView = CalculatorView()

    init() {
        setupView()
        setupActions()
    }

    private func setupView() {
        // 뷰 초기화 및 설정
    }

    private func setupActions() {
        calculatorView.addButton.addTarget(self, action: #selector(addButtonTapped), for: .touchUpInside)
        calculatorView.subtractButton.addTarget(self, action: #selector(subtractButtonTapped), for: .touchUpInside)
    }

    @objc private func addButtonTapped() {
        let inputNumber = // 사용자로부터 입력받은 숫자
        calculatorModel.add(inputNumber)
        updateView()
    }

    @objc private func subtractButtonTapped() {
        let inputNumber = // 사용자로부터 입력받은 숫자
        calculatorModel.subtract(inputNumber)
        updateView()
    }

    private func updateView() {
        calculatorView.resultLabel.text = "\\(calculatorModel.result)"
    }
}

참고 자료

SwiftUI에서 ViewController를?

MVVM

Model-View-ViewModel

MVVM은 SwiftUI의 특징과 잘 어울려 UI 코드를 간결하게 유지하면서도 코드의 유지보수성과 확장성을 높일 수 있습니다. 바인딩, 그리고 UI 상태의 효과적인 관리와 업데이트에 있습니다.

Model (모델):

  • 데이터와 비즈니스 로직을 담당합니다.
swiftCopy code
struct Task {
    var title: String
    var isCompleted: Bool
}

class TaskManager {
    var tasks: [Task] = []

    func addTask(title: String) {
        let newTask = Task(title: title, isCompleted: false)
        tasks.append(newTask)
    }

    // 다른 작업 관련 메서드들...
}

ViewModel (뷰모델):

  • 뷰에서 사용되는 데이터와 해당 데이터를 처리하는 로직을 담당합니다.
swiftCopy code
import SwiftUI

class TaskListViewModel: ObservableObject {
    @Published var tasks: [Task] = []
    private var taskManager = TaskManager()

    init() {
        // 뷰모델 초기화 및 기본 데이터 설정
        self.tasks = taskManager.tasks
    }

    func addTask(title: String) {
        taskManager.addTask(title: title)
        tasks = taskManager.tasks
    }

    // 다른 뷰모델 메서드들...
}

View (뷰):

  • 사용자 인터페이스를 나타내며, 뷰모델과 바인딩하여 데이터의 상태를 반영합니다.
swiftCopy code
import SwiftUI

struct TaskListView: View {
    @ObservedObject var viewModel: TaskListViewModel
    @State private var newTaskTitle = ""

    var body: some View {
        VStack {
            TextField("New Task", text: $newTaskTitle)
                .padding()
            Button("Add Task") {
                viewModel.addTask(title: newTaskTitle)
                newTaskTitle = ""
            }
            List(viewModel.tasks) { task in
                Text(task.title)
                    .foregroundColor(task.isCompleted ? .green : .black)
            }
        }
        .padding()
    }
}

참고 자료

https://www.youtube.com/watch?v=uQtM6StTsQg

TCA

  1. View 단독으로 ViewModel의 역할 가능 기존 MVVM의 ViewModel은 데이터 바인딩을 위해 필요하지만 SwiftUI는 View 자체적으로 데이터 바인딩이 가능한 PropertyWrapper를 지원하기에 ViewModel이 더 이상 필요 없다는 의견으로 아래 코드를 비교해 보면 View에서 간단하게 처리 가능한 내용을 ViewModel을 이용할 때 복잡해지는 예를 확인할 수 있습니다.
  1. SwiftUI와 데이터 흐름의 충돌 선언형 언어인 SwiftUI에서 데이터 흐름은 단방향을 지향하는데 ViewModel은 데이터의 흐름을 양방향으로 만들고 복잡도를 증가시킨다.아래 그림 처럼 ViewModel이 View와 연동될 때 명확한 구조가 없어 개발 상황에 따라 데이터를 주고받으면서 서로 강하게 엮이는게 상황이 발생할 수 있다는 논리로 설명하고 있습니다.

TCA의 데이터 흐름

모든 구성요소의 데이터 흐름이 단방향으로 이동하고 있고 각 구성 요소는 Store로 관리되며 Dependency는 Store의 외부에서 주입해 사용하는 것을 알 수 있습니다.

TCA의 데이터 흐름은 아래 그림과 같이 표현할 수 있습니다.

  • State : 비즈니스 로직을 수행하거나 UI를 그릴 때 필요한 데이터의 집합
  • Action : 사용자로부터 발생하는 이벤트나 노티피케이션등 뷰에서 생길 수 있는 모든 action과 API호출 결과를 나타내는 타입입니다.
  • Dependency : 외부 시스템과 상호 작용하는 유형과 기능을 말하며 대표적으로 API 클라이언트가 있고 UUID나 Date의 초기화등도 포함합니다.
  • Effect : 네트워크 요청, 디스크에서 저장/로드, 타이머 생성, Dependency와 상호 작용과 같은 작업을 수행하며 Reduce()의 리턴값으로 사용됩니다.
  • Reduce : Action을 전달받아 이를 처리 후 결과를 State의 상태를 변경해 UI를 업데이트하도록 하는 로직을 구현하는 메서드입니다.API 요청과 같은 이벤트를 Effect와 Dependency를 이용해 실행하고 Action을 이용해 결과를 다시 전달합니다.
  • Store : 실제로 TCA의 여러 기능을 실행할 수 있는 오브젝트로 사용자 액션을 스토어로 전송하여 Reducer와 Effect를 실행할 수 있도록 하고 스토어의 상태 변화를 관찰하여 UI를 업데이트할 수 있습니다.

참고 자료

네이버페이 워치앱 SwiftUI TCA 적용기

결론

MVVM 패턴 없이 사용을 해보려고 하였지만 TCA 도입을 하려면 시간비용을 많이 투자하여 도입을 해야할 것 같다. 단방향 데이터 흐름이 우리앱에 더 잘맞을 것 같지만 TCA 도입을 하기 위한 비용이 커서 이야기 해보면 좋을 것 같습니다.

 

728x90

'Swift > 정리' 카테고리의 다른 글

[SwiftDataStructure&Algorithms] 데이터 구조  (1) 2024.03.12
XCODE IOS 프로파일링 디버깅 하는 방법  (1) 2024.01.07
[SwiftUI] Combine - 기본  (0) 2023.09.16
[SwiftUI] Combine  (0) 2023.09.16
[Swift] SwiftLint  (0) 2023.09.04
'Swift/정리' 카테고리의 다른 글
  • [SwiftDataStructure&Algorithms] 데이터 구조
  • XCODE IOS 프로파일링 디버깅 하는 방법
  • [SwiftUI] Combine - 기본
  • [SwiftUI] Combine
bulmang
bulmang
모바일 개발자 도전
  • bulmang
    bulmang
    bulmang
  • 전체
    오늘
    어제
    • 분류 전체보기 (208)
      • 알고리즘 (68)
        • List (3)
        • Two Pointer (6)
        • Binary Search (4)
        • Prefix Sum (3)
        • Sort (4)
        • Brute Force (5)
        • Array (2)
        • String (4)
        • 프로그래머스 (12)
        • 백준 (9)
        • Queue (2)
        • Stack (2)
        • Recursion (12)
      • Computer Science (16)
        • Computer Architecture (6)
        • Operating System (5)
        • Network (2)
        • 기타 (2)
        • System Programming (1)
      • Swift (70)
        • 개발 (24)
        • 정리 (25)
        • 문법 (20)
      • Flutter (24)
      • 기타 (12)
        • 후기 (12)
      • Git (6)
      • Ios 오픈소스 (5)
      • UI 디자인 (5)
      • AppleScript (2)
  • 링크

    • Notion
    • Github
  • 태그

    Swift
    코딩테스트
    피플
    컴퓨터구조
    today i learned
    개발
    백준
    알고리즘
    SwiftUI
    재귀
    riverpod
    협업
    til
    FLUTTER
    Xcode
    문법
    Java
    자료구조
    Apple Developer Academy
    IOS
  • 최근 댓글

  • 최근 글

  • 인기 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.2
bulmang
[SwiftUI] 아키텍처 고민
상단으로

티스토리툴바