[Swift] MVVM 구조 이해하기

Oni·2023년 9월 19일
1

TIL

목록 보기
47/47
post-thumbnail

? : 이번 과제는 MVVM 구조로 진행해보세요~
ㄴ ? 네?? ???????? MVVM이 뭐지...

MVVM에 대한 가이드라인은 정해진 바가 없기 때문에 개발을 기획하면서, 작업하면서 맞다고 판단되는 방향으로 작업하면 된다고 하는데.. 그게 더 어렵다..
뭔지도 모르는데 가이드라인도 없다? 너무 혼란스럽다..
그래서 해당 패턴에 대해 알아볼 필요가 있다.

MVVM

Model-View-ViewModel의 약자로, 소프트웨어 개발에서 사용되는 아키텍처 패턴 중 하나를 말한다.
MVVM은 애플리케이션을 세 가지 주요 컴포넌트로 분리하여 관리하며, 각 컴포넌트가 특정 역할을 담당한다.

Model(모델)

  • 애플리케이션의 데이터와 비즈니스 로직을 포함
  • 데이터베이스, 네트워크 요청, 로컬 저장소 등과 상호 작용하여 데이터를 가져오고 업데이트 함
  • 애플리케이션의 상태와 데이터를 표현하며, 데이터 변경을 감지하고 알림을 전달할 수 있음
import Foundation
import CoreData

@objc(Task)
public class Task: NSManagedObject {

}

View(뷰)

  • 사용자 인터페이스(UI)
  • 사용자가 애플리케이션과 상호 작용할 수 있는 화면을 구성하고 사용자 입력을 받음
  • 사용자에게 데이터를 표시하고 사용자 입력을 ViewModel에 전달함
import SnapKit
import UIKit

class BucketListView: UIView {
    let tableView: UITableView = {
        let tableView = UITableView()
        tableView.backgroundColor = UIColor(red: 248/255, green: 248/255, blue: 248/255, alpha: 255)
        tableView.separatorColor = .systemGray
        tableView.register(BucketListCell.self, forCellReuseIdentifier: BucketListCell.identifier)
        return tableView
    }()

    let addButton: UIBarButtonItem = {
        let addButton = UIBarButtonItem()
        addButton.image = UIImage(systemName: "plus.circle.fill")
        return addButton
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)

        setupUI()
    }

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

    private func setupUI() {
        addSubview(tableView)

        tableView.snp.makeConstraints { make in
            make.top.leading.trailing.bottom.equalToSuperview()
        }
    }
}

ViewModel(뷰 모델)

  • 뷰와 모델 사이의 중간 계층 역할
  • 모델로부터 데이터를 가져와서 뷰가 사용하기 쉬운 형태로 가공하고 포맷함
  • 사용자 인터페이스와 관련된 로직을 처리하고, 뷰에 데이터를 제공함
  • 뷰와 완전히 분리되어 있으며, 뷰의 생명주기와 독립적으로 동작함
  • 주로 사용자의 입력을 처리하고, 데이터를 표시하고 감시하려 변경 사항을 뷰에 알림
import Foundation
import UIKit

class BucketListViewModel {
    private let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    var bucketList: [Task]?
    var tableViewReloadHandler: (() -> Void)?

    func fetchBucketList() {
        let request = Task.fetchRequest()

        do {
            bucketList = try context.fetch(request)
            tableViewReloadHandler?()
        } catch {
            print("🚨 Error: Fetch Task")
        }
    }
    
    ...
    
}

MVVM 패턴은 주로 데이터 바인딩과 함께 사용되어, 모델의 변경 사항이 자동으로 뷰에 반영되도록 한다. 이로써 코드의 가독성을 향상시키고 유지보수를 용이하게 해준다.


장단점

장점

  • 뷰와 로직의 분리: 뷰 코드와 비즈니스 로직 코드가 서로 혼재하지 않아 유지 보수가 더 쉬움
  • 테스트 용이성: ViewModel은 순수한 비즈니스 로직을 포함하고 있으며, 이 로직을 독립적으로 테스트하기 쉬움
  • 재사용성: 동일한 비즈니스 로직을 여러 뷰에서 사용하거나 다른 프로젝트에서 재사용할 수 있음
  • 데이터 바인딩: 데이터 바인딩을 사용하면 뷰와 ViewModel 간의 데이터 흐름을 자동화할 수 있으며 UI 업데이트가 간편해짐

데이터 바인딩(Data Binding)
소프트웨어 개발에서 사용자 인터페이스(UI)와 데이터 모델을 연결하는 기술 또는 패턴이다. 주로 MVVM (Model-View-ViewModel) 아키텍처와 함께 사용되며 UI 요소의 상태와 데이터 모델 간의 동기화를 자동화한다. 데이터 바인딩은 데이터 모델의 변경 사항이 자동으로 UI에 반영되고, UI의 상태 변경이 데이터 모델에 자동으로 반영되도록 해준다.

단점

  • 초기 학습 곡선: MVC 보다 헷갈려서 초기 학습 곡선이 높음. 특히 데이터 바인딩과 라이브러리를 사용해야 하는 경우 더 많은 학습 시간이 필요할 수 있음
  • 불필요한 복잡성: 간단한 애플리케이션의 경우 MVVM 패턴을 도입하는 것이 불필요한 복잡성을 초래할 수 있음. 간단한 애플리케이션의 경우 MVC(Modal-View-Controller) 등 다른 패턴을 사용하는게 더 효율적임
  • 성능 오버헤드: 데이터 바인딩과 같은 MVVM의 기능은 성능 오버헤드를 유발할 수 있음. 특히 대규모 애플리케이션의 경우 성능 문제에 대한 고려가 필요함.
  • 경험이 필요함: MVVM 패턴을 올바르게 구현하려면 경험이 필요함. 가이드라인이 없기 때문에 설계를 어떻게 하냐에 따라 달라짐. 특히 복잡한 데이터 흐름과 비즈니스 로직을 다룰 때 더 많은 경험이 요구됨

말 그대로 MVVM은 모델, 뷰, 뷰모델로 구분하는 것이며, 본패턴에 익숙해지기까지는 시간이 좀 걸릴 것 같다.
지금 진행중인 프로젝트에 MVVM을 적용해보고 있는데, 아직까지 뷰모델과 뷰컨트롤의 역할을 어떻게 나눠야 하고 어떤 코드를 작성해야 하는지 혼란을 느끼고 있다.
그렇지만, MVVM의 장점인 뷰의 완벽한 분리에 대해서는 어느정도 이해가 된다. 내일은 뷰컨트롤에 있는 코드들을 어떤 기준으로 뷰모델로 뺄 지 고려하여 리팩토링 해보려고 한다.

profile
하지만 나는 끝까지 살아남을 거야!

0개의 댓글