티스토리 뷰

반응형

 

 

 

안녕하세요 멍구입니다. ^-^//

오늘은 MVC의 MassiveViewController 문제를 해결할 수 있는 디자인패턴, MVVM패턴의 코드 구현 연습을 Swift언어를 사용해서 해볼까 합니다. 🤩

바로 시작하겠습니다.

 


MVVM패턴 Swift 코드로 구현 해보기

MVVM은 Model-View-ViewModel의 구성을 갖습니다.
먼저 이중에 Model을 구현해보겠습니다. 보통 Model은 Class, Struct등으로 정의됩니다. 아래에서 바로 코드로 구현해보겠습니다. 
먼저 해당 프로젝트는 Playground에서 진행합니다. MVVM의 구현결과는 Playground의 LiveView에서 볼 예정입니다.

구현하기에 앞서 먼저, UIView를 Playground의 LiveView에서 표출하기 위해 두개의 프레임워크를 import 해줍니다.

이제 차례대로 구현해 보도록 할까요? 👍🏼

 


Model
모델 구성하기

모델로는 class로 Pet을 정의합니다. 코드는 아래와 같습니다.

import PlaygroundSupport
import UIKit

// MARK: Model

// - 예를 들면, pets를 채택하는 앱의 일부로서 Pet View를 만들 수 있습니다. 먼저, 아래와 같은 코드를 작성합니다.
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은 그 자체의 희소성을 구분하는 Rarity 열거형과 이름, 생일, 희귀성, 이미지의 멤버를 갖습니다.
또한 이러한 값들을 생성자로 받아 초기화 됩니다. Pet class는 모델(Model)입니다.

해당 모델은 독자적으로 View에 표출되어질 수 없습니다. Model은 ViewModel을 거쳐 View에 표출됩니다. MVVM의 ViewModel을 통해 View에 표출될 값으로 변환되어 사용되어집니다. 


이어서 ViewModel을 구현하겠습니다.

 


ViewModel
뷰 모델 구성하기

뷰모델은 Pet Model을 View에 표출할 수 있는 값으로 변환해줍니다. 그 코드는 아래와 같습니다.

// MARK: ViewModel

public class PetViewModel {
    // 1) pet : Pet 객체를 생성합니다. 나이 연산을 위해 Calendar도 생성합니다.
    private let pet: Pet
    private let calendar: Calendar

    public init(pet: Pet) {
        self.pet = pet
        calendar = Calendar(identifier: .gregorian)
    }

    // 2) name : 펫의 이름을 반환합니다.
    public var name: String {
        return pet.name
    }

    // image : 펫의 이미지를 반환합니다.
    public var image: UIImage {
        return pet.image
    }

    // 3) ageText : 펫의 나이를 연산하며 반환합니다. 몇살인지를 표출합니다.
    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) adoptionFeeText : 해당 펫의 희귀성에 따른 가격을 결정합니다. 
    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"
        }
    }
}

위의 코드는 Model, Pet이 거치게 되는 뷰모델, PetViewModel을 정의하고 있습니다.
위 주석에 번호 매긴 부분을 하나하나 돌아보도록 하겠습니다.

1) 먼저 pet, calendar를 생성합니다. 이들은 pet의 속성, 나이 등을 변환 및 반환하는데에 사용되어집니다. 생성자로 해당 값들은 초기화됩니다.

2) 그 다음 name, image를 위한 두개의 계산 프로퍼티를 선언합니다. name, image는 pet에 대해 표출되어야 하는 이름, 이미지 값을 반환할 때 사용되어집니다. 이는 Model의 값을 ViewModel에서 변환하는 가장 쉬운 방법의 예가 됩니다. 만약 펫의 이름 접두어를 수정하고 싶다면, ViewModel의 해당 부분에서 이름 구조를 수정하면 끝입니다.

3) 세번째로, 또 다른 계산 프로퍼티, ageText를 선언합니다. ageText 값 변환 시에는 오늘부터 ~ pet의 생일까지의 시간 차이를 계산하기 위해 calendar를 활용하고 있습니다. 여기에 "years old" 문자열이 따라오게 됩니다. 이후 어떠한 String 문자열 포멧 작업 없이 해당 값(ageText)를 뷰에 띄울 수 있습니다.

4) 마지막으로, 계산 프로퍼티로서 adoptionFeeText를 생성할 수 있습니다. adoptionFeeText에서는 rarity에 기반한 pet의 입양비용을 결정할 수 있습니다. 또한 이러한 값을 String 문자열로서 반환할 수 있습니다. 

지금까지 MVVM의 Model인 Pet, ViewModel인 PetViewModel이 정의되었습니다.
마지막으로 Model이 ViewModel을 거쳐 표현되어질, 실제로 화면에 표출되어질 View를 정의해야겠죠?

View는 UIView로서 정의됩니다. 그러므로 UIKit을 import 해주어야 합니다.

 

 


View
뷰 구성하기

// 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
        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")
    }
}

위의 코드는 MVVM의 View를 구현한 예시입니다.

해당 코드에서 총 4개의 서브뷰(subView)를 포함한 PetView를 선언하고 있습니다. 해당 뷰에서 pet의 이미지, 이름, 나이, 입양비를 표현하는 세개의 라벨을 중앙정렬하여 띄웁니다. 이 때 각각의 뷰에 대한 위치, 크기를 init(frame:)에서 설정할 수 있습니다. 마지막으로, 해당 뷰가 지원되지 않는다면, init?(coder:)에서 fatalError를 실행하여 런타임 크래시를 일으키도록 하고 있습니다. 

 

 


자, 이렇게 Swift(스위프트) 언어를 사용한 MVVM의 구성 요소인 Model, ViewModel, View가 준비되었네요! 🤩

이제 해당 코드들을 Playground의 LiveView에 동작시킬 준비가 임박되었습니다. 다음 포스팅에서 LiveView에 뷰를 셋팅하고 표출을 해보는 과정을 정리해보겠습니다. 👨🏻‍💻

 

 

* 출처 : Design Patterns by Tutorials (lay wenderLich)

 

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함