Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

프로젝트 매니저 [STEP 2-1] Moon #307

Open
wants to merge 24 commits into
base: ic_9_etialmoon
Choose a base branch
from

Conversation

hojun-jo
Copy link

@havilog
안녕하세요 하비!
프로젝트 매니저 STEP 2-1 PR 입니다!
조언 해주신 것을 참고하여 테이블 뷰 하나에서 데이터를 보여주는 것을 MVVM으로 구현해 보았습니다.

고민했던 점

Cell에서 데이터 바인딩

Cell은 재사용 되고 어떤 액션도 없는 상태이기 때문에 데이터를 받아오는 방법을 고민했습니다.
재사용 될 때마다 ViewModel을 주입받아 listCellViewModel 프로퍼티가 바뀔 때마다 바인딩 할 수 있도록 구현했습니다.

// ListCell이 재사용 될 때마다 setUpViewModel을 통해 값이 들어오면 바인딩 함
private var listCellViewModel: ListCellViewModel? {
    didSet {
        setUpBindings()
    }
}
// ListCell이 재사용 될 때 ListCellViewModel을 받아옴
func setUpViewModel(_ viewModel: ListCellViewModel) {
    self.listCellViewModel = viewModel
}
// viewModel을 받을 때마다 바인딩할 것
private func setUpBindings() {
    listCellViewModel?.bindTitle { [weak self] viewModel in
        self?.titleLabel.text = viewModel.title
    }
    
    listCellViewModel?.bindDescription { [weak self] viewModel in
        self?.descriptionLabel.text = viewModel.description
    }
    
    listCellViewModel?.bindDeadline { [weak self] viewModel in
        self?.deadlineLabel.text = viewModel.deadline
    }
}

헤더와 데이터 바인딩

테이블 뷰의 헤더에 목록의 개수를 표시하는 부분이 있어 뷰 모델과 바인딩이 필요하다고 생각했습니다.
따라서 다음과 같이 모델이 변경 되었을 때 헤더가 바인딩하고 있는 프로퍼티도 바뀔 수 있도록 구현했습니다.

final class ListViewModel {
    // ListViewController에서 ListCell의 ListCellViewModel로 전달하게될 모델의 배열
    private var todoList: [Todo] {
        didSet {
            count = String(todoList.count)
        }
    }
    // ListHeader의 contentAmountLabel와 바인딩할 변수
    var count: String {
        didSet {
            bindCount?(self)
        }
    }
    // ListHeader의 contentAmountLabel와 바인딩하기 위한 클로저
    private var bindCount: ((ListViewModel) -> Void)?
...
}

조언을 얻고 싶은 점

모델 생성 시점

현재는 ListViewModel을 초기화하며 임의로 데이터를 넣어둔 상태입니다.

final class ListViewModel {
...
    init() {
        todoList = [
            Todo(title: "1", description: "111", deadline: Date()),
            Todo(title: "2", description: "222", deadline: Date()),
            Todo(title: "3", description: "333", deadline: Date()),
            ...
        ]
        
        count = String(todoList.count)
    }
...
}

하지만 저장소에 데이터를 저장 해두고 모델에서 불러와 사용한다고 했을 때 어느 시점에 초기화하는 것이 좋을 지 잘 모르겠습니다.
제가 생각한 방법은 다음과 같습니다.

  1. SceneDelegate에서 모델 생성 -> 이 모델을 주입 받아 뷰 모델 생성 -> 이 뷰 모델을 주입 받아 뷰 컨트롤러 생성
  • 이 경우 SceneDelegate에서 데이터를 가져오는 로직을 수행하게 되는 것 같아 적절하지 않은 것 같습니다.
  1. 뷰 모델에서 모델을 초기화하며 저장소에서 데이터를 가져오는 로직 수행
  • 뷰 모델은 프레젠테이션 로직을 수행하는 것으로 알고 있는데 데이터를 가져오는 로직을 수행하게 되는 것은 적절하지 않은 것 같습니다.
  1. 모델 자체에서 초기화되며 데이터를 가져오는 로직 수행
  • 데이터를 가지고 있고 비즈니스 로직을 수행 해야하는 모델이 직접 이 작업을 하는 것이 괜찮은 것인지 모르겠습니다.

뷰 모델의 역할

테이블 뷰의 numberOfRowsInSectiontodoList의 개수가 되어야하고 cellForRowAt에서는 Todo 모델이 필요하기 때문에 뷰 모델에서 이를 리턴하고 있습니다.
뷰 모델의 역할은 프레젠테이션 로직을 수행하는 것인데 이런 로직을 수행해도 괜찮은 부분일까요?

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return listViewModel.countTodo()
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: ListCell.identifier) as? ListCell else {
            return UITableViewCell()
        }
        
        let todo = listViewModel.getTodo(index: indexPath.row)
        
        cell.setUpViewModel(ListCellViewModel(todo: todo))
        
        return cell
    }

Copy link

@havilog havilog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨어요

Comment on lines +11 to +13
var title: String
var description: String
var deadline: Date
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 아이들을 variable로 선언하신 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

할 일을 수정할 수 있기 때문에 계속 변경될 거라 생각해 variable로 선언했습니다!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 프로퍼티의 값이 변경될 일이 잦으면 class가 더 적합한 거 같고,
할 일을 수정하는건 할 일을 담당하는 객체가 가지고 있는 todo의 인스턴스가 변경될거 같아요

Copy link
Author

@hojun-jo hojun-jo Oct 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 변경될 일이 잦으면 class가 더 적합하겠군요
코어데이터를 사용하면 지금의 구조체를 사용하지 않고 NSManagedObject인 todo를 사용해서 값이 변경되면 뷰모델이 데이터매니저에게 저장하도록 만들 것 같습니다!

ProjectManager/ProjectManager/View/ListCell.swift Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants