- This topic has 2개 답변, 2명 참여, and was last updated 4 years, 8 months 전에 by 5anniversary.
-
글쓴이글
-
-
5anniversary참가자
- 글작성 : 14
- 답글작성 : 7
안녕하세요 🙂
오늘은 이번학기 새로 시작할 프로젝트를 MVVM 디자인 패턴으로 프로젝트를 만들어가기 위해,
MVVM 디자인 패턴에 대해 살짝쿵 공부를 해보았습니다.이번 프로젝트에서 MVVM 디자인 패턴으로 구조를 구성하기로 생각을 한 이유는 현재 진행중인 동아리 프로젝트에서는 MVC로 하는데 점점 가면 갈수록, 프로젝트가 비대해질수록, 프로젝트의 구조를 파악하고 고쳐야할 부분을 찾기가 힘들다는 점이 가장 컸습니다.
MVVM 디자인 패턴의 기본적인 구조를 그려놓은 이미지입니다
아무튼!!Model은 어플리케이션 데이터를 가지고 있고, Model들은 보통 struct나 간단한 class로 구성됩니다,
View는 스크린에 보여지고, 컨트롤하는 구조입니다. 보통은 UIView로 만들어집니다
ViewModel은 model 정보를 view에 표시할수있는 값으로 변환합니다. 보통 Class로 만들어지기 때문에 reference로 사용될 수 있습니다.
이런 기본적인 구조를 파악했으니 코드가 어떻게 구성되는지 보면서 디자인 패턴에 대해 파악을 해볼까요?
아래의 예제 코드들은 참고에 있는 페이지에서 가져왔습니다.
import PlaygroundSupport import UIKit // MARK: - Model public class Pet { public enum Rarity { case common case uncommon case rare case veryRare } public let name: String public let birthday: Date public let rarity: Rarity public let image: UIImage public init(name: String, birthday: Date, rarity: Rarity, image: UIImage) { self.name = name self.birthday = birthday self.rarity = rarity self.image = image } }
Pet이라는 이름을 가진 Model에서 모든 pet에게 있을 name, birthday, rarity, image를 정의해줍니다.
name과 image의 경우에는 View에 바로 표시할 수 있지만, birthday와 rarity의 경우에는 View에서 바로 표시를 할 수 없기때문에 ViewModel에서 변형이 필요합니다.// MARK: - ViewModel public class PetViewModel { // 1 private let pet: Pet private let calendar: Calendar public init(pet: Pet) { self.pet = pet self.calendar = Calendar(identifier: .gregorian) } // 2 public var name: String { return pet.name } public var image: UIImage { return pet.image } // 3 public var ageText: String { let today = calendar.startOfDay(for: Date()) let birthday = calendar.startOfDay(for: pet.birthday) let components = calendar.dateComponents([.year], from: birthday, to: today) let age = components.year! return "(age) years old" } // 4 public var adoptionFeeText: String { switch pet.rarity { case .common: return "$50.00" case .uncommon: return "$75.00" case .rare: return "$150.00" case .veryRare: return "$500.00" } } }
ViewModel에서 위 코드에서 한 일들을 정리해보면
- pet과 calenadar라는 두 개의 private property를 만들고 init에서 초기화를 시켜줍니다.
- name과 image에 대해 pet 프로퍼티에서 받아옵니다.
- pet의 birthday에서 받아와 계산을 하는 ageText를 선언합니다. retrun은 O years old로 계산됩니다.
- 마지막으로 pet의 rarity에서 enum을 받아와 return되는 값을을 switch문으로 정의합니다.
이 다음으로는 UIView에서 ViewModel의 계산 방식을 가지고 사용자에게 보여줍니다.
// MARK: - View public class PetView: UIView { public let imageView: UIImageView public let nameLabel: UILabel public let ageLabel: UILabel public let adoptionFeeLabel: UILabel public override init(frame: CGRect) { var childFrame = CGRect(x: 0, y: 16, width: frame.width, height: frame.height / 2) imageView = UIImageView(frame: childFrame) imageView.contentMode = .scaleAspectFit childFrame.origin.y += childFrame.height + 16 childFrame.size.height = 30 nameLabel = UILabel(frame: childFrame) nameLabel.textAlignment = .center childFrame.origin.y += childFrame.height ageLabel = UILabel(frame: childFrame) ageLabel.textAlignment = .center childFrame.origin.y += childFrame.height adoptionFeeLabel = UILabel(frame: childFrame) adoptionFeeLabel.textAlignment = .center super.init(frame: frame) backgroundColor = .white addSubview(imageView) addSubview(nameLabel) addSubview(ageLabel) addSubview(adoptionFeeLabel) } @available(*, unavailable) public required init?(coder: NSCoder) { fatalError("init?(coder:) is not supported") } }
위 PetView에서는 사용자에게 보여줄 4가지의 subView를 만듭니다.
먼저 petView의 크기와 위치를 정의해주고
각각 4가지의 subView의 위치와 크기를 지정해줍니다.// MARK: - Example // 1 let birthday = Date(timeIntervalSinceNow: (-2 * 86400 * 366)) let image = UIImage(named: "stuart")! let stuart = Pet(name: "Stuart", birthday: birthday, rarity: .veryRare, image: image) // 2 let viewModel = PetViewModel(pet: stuart) // 3 let frame = CGRect(x: 0, y: 0, width: 300, height: 420) let view = PetView(frame: frame) // 4 view.nameLabel.text = viewModel.name view.imageView.image = viewModel.image view.ageLabel.text = viewModel.ageText view.adoptionFeeLabel.text = viewModel.adoptionFeeText // 5 PlaygroundPage.current.liveView = view
마지막으로 사용자에게 보여지는 class부분입니다
해당하는 코드는 playground로 작성이 되어있기 때문에 보시는 여러분들이 Single View App에서 사용하실때에는 UIViewController에서 사용을 해주시면 되겠습니다.
사용한 방법은
1. stuart의 이름을 가진 Pet을 생성해주고
2. 생성한 stuart를 사용해 ViewModel을 생성해줍니다.
3. 미리 만들어둔 petView를 이용해 view를 생성해줍니다.
4. 위 코드에서 만들어둔 petViewModel을 이용해 view안에 넣어줍니다.
5. 마지막으로 사용자에게 보여주는 코드!!입니다.위와 같은 구조로 사용되는 MVVM인데요 하나씩 정리를 하면서 보니깐
이해가 어렵지는 않네요.Model을 만들어 구조를 잡아준 다음!
ViewModel에서 출력될 값들을 정의해주고,
View를 만들어 사용자에게 보여질 UI를 구성한 뒤
UIViewController에서 구조에 맞는 값들을 ViewModel에 넣어 View를 통해 보여주는 구조로 이해했습니다.- 이 게시글은 5anniversary에 의해 4 years, 8 months 전에 수정됐습니다.
- 이 게시글은 5anniversary에 의해 4 years, 8 months 전에 수정됐습니다.
- 이 게시글은 5anniversary에 의해 4 years, 8 months 전에 수정됐습니다.
2020-04-12 오전 2:28 #6565 -
5anniversary참가자
- 글작성 : 14
- 답글작성 : 7
- ViewModel은 직접적으로 상속을 받고 있고 class의 경우에는 call by reference로 알고있습니다. 따라서 Model보다 좀 더 자세한 내용이 쓰여있는 ViewModel의 경우에는 사이즈가 크기때문에 class를 사용한다고 이해했습니다!
- 두번째 질문에 대해서는 좀 더 공부를 하고 답변하겠습니다! 단순히 번역을 통해 작성한 코드이고 의례적으로 사용한 public이라 좀 더 자세한 공부를 해야할 것 같습니다!!
2020-04-12 오후 3:56 #6601
-
-
글쓴이글
- 답변은 로그인 후 가능합니다.