4T2F / ThinkBig

🌟씽크빅 스터디🌟
5 stars 1 forks source link

MVVM-C(Coordinator) 아키텍처 패턴에 대해 설명해주세요. #72

Open JooYoungNoh opened 4 months ago

JooYoungNoh commented 4 months ago
JooYoungNoh commented 4 months ago

MVVM-C 패턴

기존 화면 전환



코디네이터 화면 전환



계층별 역할

Model

View

ViewModel

Coordinator



장단점

장점

책임 분리


테스트 용이성


재사용성


유연성



단점

어려움


코드 양 증가


과도한 분리



적용 사례

큰 규모의 앱


복잡한 UI 흐름


테스트 가능성이 높은 비즈니스 로직



구현 방법

👉 전체코드

Model

struct ToDo {
    var title: String
    var description: String
    var completed: Bool
}


ViewModel

class ToDoListViewModel {
    var toDoList: [ToDo] = [
        ToDo(title: "Grocery shopping", description: "Buy milk, eggs, bread, and cheese.", completed: false),
        ToDo(title: "iOS Project", description: "Work on the SwiftUI to-do list app.", completed: false),

        ~~~

        ToDo(title: "Learn Guitar", description: "Practice guitar chords for at least 20 minutes.", completed: true),
        ToDo(title: "Call Parents", description: "Have a catch-up call with mom and dad.", completed: true)
    ]

    func saveTodo(title: String, description: String) {
        self.toDoList.append(ToDo(title: title, description: description, completed: false))
    }

    func changeToDo(row: Int, title: String, description: String, completed: Bool) {
        toDoList[row] = ToDo(title: title, description: description, completed: completed)
    }
}


View

class ToDoListView: UIViewController {
    weak var coordinator: ToDoListCoordinator?
    var viewModel: ToDoListViewModel?

    ~~ 대충 뷰 그리는 함수

//MARK: 액션 메소드
extension ToDoListView {
    @objc func addButtonClick(_ sender: UIBarButtonItem) {
        coordinator?.showAddToDoListView()
    }
}

~~~

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        coordinator?.showDetailToDoListView(row: indexPath.row)
    }
class DetailToDoListView: UIViewController {
    weak var coordinator: DetailToDoListCoordinator?
    var viewModel: ToDoListViewModel?

    var listItem: ToDo
    var row: Int

    init(coordinator: DetailToDoListCoordinator?, viewModel: ToDoListViewModel, listItem: ToDo, row: Int) {
        self.coordinator = coordinator
        self.viewModel = viewModel
        self.listItem = listItem
        self.row = row
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    ~~~ 대충 뷰 그리는 함수

//MARK: 버튼 메소드
extension DetailToDoListView {
    @objc func closeButtonClick(_ sender: UIBarButtonItem) {
        coordinator?.dismiss()
    }

    @objc func saveButtomClick(_ sender: UIButton) {
        self.viewModel?.changeToDo(
            row: row,
            title: self.titleTextView.text,
            description: self.descriptionTextView.text,
            completed: self.completedSeg.selectedSegmentIndex == 1 ? true : false)

        coordinator?.dismiss()
    }
}


Coordinator

protocol Coordinator: AnyObject {
    var childCoordinators: [Coordinator] { get set }
    var navigationController: UINavigationController { get set }

    func start()
}

class AppCoordinator: Coordinator {
    var childCoordinators: [Coordinator] = []
    var navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() {
        let coordinator = ToDoListCoordinator(navigationController: navigationController)
        coordinator.start()
        childCoordinators.append(coordinator)
    }
}
 guard let windowScene = (scene as? UIWindowScene) else { return }

        let navigationController = UINavigationController()
        coordinator = AppCoordinator(navigationController: navigationController)
        coordinator?.start()

        window = UIWindow(windowScene: windowScene)
        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()


class ToDoListCoordinator: Coordinator {
    var childCoordinators: [Coordinator] = []
    var navigationController: UINavigationController

    var viewModel = ToDoListViewModel()

    let vc = ToDoListView()

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func start() {
        vc.coordinator = self
        vc.viewModel = viewModel

        navigationController.pushViewController(vc, animated: true)
    }

    func showAddToDoListView() {
        let coordinator = AddToDoListCoordinator(navigationController: navigationController, viewModel: viewModel)
        coordinator.delegate = self
        coordinator.start()
        childCoordinators.append(coordinator)
    }

    func showDetailToDoListView(row: Int) {
        let coordinator = DetailToDoListCoordinator(
            navigationController: navigationController,
            viewModel: viewModel,
            listItem: self.viewModel.toDoList[row],
            row: row)
        coordinator.delegate = self
        coordinator.start()
        childCoordinators.append(coordinator)
    }
}

extension ToDoListCoordinator: AddToDoDelegate {
    func reloadData() {
        self.vc.tableView.reloadData()
    }

    func dismiss(coordinator: AddToDoListCoordinator) {
        childCoordinators = childCoordinators.filter { $0 !== coordinator }
    }
}

extension ToDoListCoordinator: DetailToDoDelegate {
    func dismiss(coordinator: DetailToDoListCoordinator) {
        childCoordinators = childCoordinators.filter { $0 !== coordinator }
    }
}