• Jan
  • Feb
  • Mar
  • Apr
  • May
  • Jun
  • Jul
  • Aug
  • Sep
  • Oct
  • Nov
  • Dec
  • Sun
  • Mon
  • Tue
  • Wed
  • Thu
  • Fri
  • Sat
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

iOS 프로젝트에 MVVM 도입하기 - 2

기존 코드 MVVVM으로 변경해보기

Screen-Recording-2021-07-02-at-3 30 12-PM

MVC로 미리 짜 놨던 요 뷰를 MVVM으로 migration 해보려고 한다.

Model

모델은 짜 놓은 것 그대로 쓴다. (나중에 서버 통신할 땐 Decodable 등,, 추가 하겠지만)

image

서비스 함수는 API가 안 나왔으니까 넘겨두고, 더미데이터로 진행한다

View Model

ViewModel에서는 Collectionview Delegate, DataSource 함수까지 다 정의 해줄 것!

image

뷰 모델 swift 파일을 만들어준다.
이제 내용을 작성할건데, 먼저 기존 MVC 패턴에서의 controller의 구성은 아래와 같다.

image

MVVM에서 중요한 포인트는 View에는 UI관련만 !! 있어야 하고,
그 외 로직들은 VM에 있어야 한다.

그래서
여기에서 initNavigationBar(), registerXib(), assignDelegation() 같은 경우는 View에 그대로 남겨놓는다.
그 외에 UICollectionViewDataSource 내부에서는
ViewModel 내의 함수를 호출만 ! 한다.

이제 ViewModel을 작성해보자 ~!~!

Class로 만들수도 있는 것 같은데, 우선 struct로 진행..!!

struct CoursesViewModel {
    
}

요렇게 만들어준다.

의존성 주입 (DI)

이제 의존성 주입을 위한 init함수를 만들어준다.

image

모델 참고하면서 작성!

struct CoursesViewModel {
  
  	let title: String
  	let description: String
  	let courseDays: Int
  	let situation: Int
  	let property: String
    
  	// 의존성 주입 (Dependency Injection)
  	init(course: Course) {
      self.title = course.title
      self.description = course.description
      self.courseDays = course.courseDays
      self.situation = course.situation
      self.property = course.property
    }
}

이렇게 해도 되고, 요 부분을 더 깔끔하게 하고 싶으면
Model에서 init 함수를 만들어준 후

struct CoursesViewModel {
  
		let course: Course
  
  	init(course: Course) {
      self.course = course
    }
}

요렇게 해줘도 된다. 깔끔 ~!!

Model에서 init함수?

struct Course {
    let id: Int
    let title: String
    let description: String
    let courseDays: Int
    let situation: Int
    let property: String
  
  	init(id: Int, title: String, description: String, courseDays: Int, situation: Int, property: String) {
      self.id = id
      self.title = title
      self.description = description
      self.courseDays = courseDays
      self.situation = situation
      self.property = property
    }
}

요렇게 만들어주면 된다.

사실 뭐… 방법은 엄청 많다.

extension CoursesViewModel {
    var title: String {
        return self.course.title
    }
    
    var description: String {
        return self.course.description
    }
    
    var courseDays: Int {
        return self.course.courseDays
    }
    
    var situation: Int {
        return self.course.situation
    }
    
    var property: String {
        return self.course.property
    }
}

이런 식으로 해 줘도 되고…

VC에서 View Model 사용하기

VC.swift 파일에서

var viewModel: CoursesViewModel!

이렇게 viewModel 변수를 만들어주고, 데이터를 넣어주면 된다.

// course data가 있다고 가정
viewModel = CoursesViewModel(course: course)

데이터에 따라 초기에 label의 text나 뭐 background color 등을 지정해주고 싶으면, didSet을 사용하면 된다.

var viewModel: CoursesViewModel! {
  didSet {
    //여기에 작성
    self.someLabel.text = viewModel.course.title
    navigationItem.title = viewModel.course.title
  }
}

뭐 이런 식으로다가..

진짜 본격적으로 View Model 작성하기

이제 진짜 뷰 모델 작성을 해볼 건데 !!

struct CoursesViewModel {
  
		let course: Course
  
  	init(course: Course) {
      self.course = course
    }
}

아까 짠 뷰 모델로는 cell만 표현 가능하고, 뷰 전체에 대한 data를 표현할 수 없다. (course는 한 cell의 데이터니까!)
그래서 아래와 같이 만들어준다.

struct CourseListViewModel {
    let courses: [Course]
}

struct CourseViewModel {
    let course: Course
    
    // 의존성 주입 (Dependency Injection)
    init(_ course: Course) {
        self.course = course
    }
}

그리고 tableview delegate, dataSource에 넘겨줄 것들을 작성해준다.

extension CourseListViewModel {
    var numberOfSections: Int {
        return 1
    }
    
    func numberOfRowsInSection(_ section: Int) -> Int {
        return self.courses.count
    }
    
    func courseAtIndex(_ index: Int) -> CourseViewModel {
        let course = self.courses[index]
        return CourseViewModel(course)
    }
}

VC에서

// MARK: - UICollectionViewDataSource

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return courseListViewModel.numberOfSections
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return courseListViewModel.numberOfRowsInSection(0)
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        switch courses[indexPath.row].situation {
        case 0:
            if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Const.Xib.Identifier.undoneCourseCollectionViewCell, for: indexPath) as? UndoneCourseCollectionViewCell {
                
                let viewModel = courseListViewModel.courseAtIndex(indexPath.row)
                cell.courseViewModel = viewModel
                cell.setButtonTitle(doingCourse: doingCourse)
                
                return cell
            }
            
        case 2:
            if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Const.Xib.Identifier.doneCourseCollectionViewCell, for: indexPath) as? DoneCourseCollectionViewCell {
                
                let viewModel = courseListViewModel.courseAtIndex(indexPath.row)
                cell.courseViewModel = viewModel
                cell.setButtonTitle(doingCourse: doingCourse)
                
                return cell
            }
        default:
            return UICollectionViewCell()
        }
    
        return UICollectionViewCell()
    }

이런 식으로 사용해주면 된다.

명심 포인트

VC에서는 UI 관련 task만 수행~!!!!!