본문 바로가기
아이폰 개발/Swift

swift MVVM 패턴 예제

by 인생여희 2021. 3. 29.

 

완성화면

 

모델

import UIKit

class Dog {


    //개품종
    enum Breed {
        case pug
        case poodle
    }
    
    let name : String       //이름
    let birthday : Date      //생일
    let breed:Breed         //품종
    let image : UIImage      //이미지
    
    
    init(name: String, birthday: Date, breed: Dog.Breed, image: UIImage) {
        self.name = name
        self.birthday = birthday
        self.breed = breed
        self.image = image
    }
}

 

import UIKit


class DogView: UIView {

    // 뷰를 스토리보드로 만들지 않고 코드로 작성시 사용
    
    //이미지 뷰
    let imageView:UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

    //이름 라벨
    let nameLabel : UILabel = {
        let nameLabel = UILabel()
        nameLabel.textAlignment = .left
        nameLabel.textColor = .white
        nameLabel.translatesAutoresizingMaskIntoConstraints = false
        return nameLabel
    }()

    //나이 라벨
    let ageLabel :UILabel = {
       let ageLabel = UILabel()
        ageLabel.textAlignment = .left
        ageLabel.textColor = .white
        ageLabel.translatesAutoresizingMaskIntoConstraints = false
        return ageLabel
    }()
    
    //가격
    let adoptionFeeLabel : UILabel = {
        let adoptionFeeLabel = UILabel()
        adoptionFeeLabel.textAlignment = .left
        adoptionFeeLabel.textColor = .white
        adoptionFeeLabel.translatesAutoresizingMaskIntoConstraints = false
        return adoptionFeeLabel
    }()
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    
        backgroundColor =  UIColor(red: 28/255, green: 28/255, blue: 30/255, alpha: 1)
        
        addSubview(imageView)
        addSubview(nameLabel)
        addSubview(ageLabel)
        addSubview(adoptionFeeLabel)
        
        //auto layout
        imageView.topAnchor.constraint(equalTo: self.topAnchor,constant: 50).isActive = true
        imageView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        imageView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1).isActive = true
        imageView.heightAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1).isActive = true
        
        //이름
        nameLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 30).isActive = true
        nameLabel.leadingAnchor.constraint(equalTo: imageView.leadingAnchor, constant: 10).isActive = true
        
        //나이
        ageLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 20).isActive = true
        ageLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor, constant: 0).isActive = true
        
        
        //나이
        adoptionFeeLabel.topAnchor.constraint(equalTo: ageLabel.bottomAnchor, constant: 20).isActive = true
        adoptionFeeLabel.leadingAnchor.constraint(equalTo: ageLabel.leadingAnchor, constant: 0).isActive = true

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

 

뷰모델

//뷰모델
import UIKit


class DogViewModel {

    let dog : Dog
    let calendar : Calendar
    
    init(dog:Dog) {
        self.dog = dog
        self.calendar = Calendar(identifier: .gregorian)
    }
    
    //이름
    var name :String{
        return dog.name
    }
    
    //이미지
    var image : UIImage {
        return dog.image
    }
    
    //나이
    var ageText : String{
        let today = calendar.startOfDay(for: Date())
        let birthday = calendar.startOfDay(for: dog.birthday)
        let components = calendar.dateComponents([.year], from: birthday, to: today)
        let age = components.year == nil ? 0 : components.year!
        
        
        return "\(age) 살"
    }
    
    
    //가격
    var adoptionFeeText : String {
        
        switch dog.breed {
         case .poodle:
            return "20000원"
         case .pug:
            return "30000원"

        }
        
    }

}

//뷰의 데이터 업데이트
extension DogViewModel{
    
    func configure(_ view:DogView) {
        view.nameLabel.text = name
        view.imageView.image = image
        view.ageLabel.text = ageText
        view.adoptionFeeLabel.text = adoptionFeeText
    }
    
}

 

컨트롤러

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
       
        print("viewdidload 진입")
        
        
        //[1]view
        let dogView = DogView()
        
        
        //[2]data
        guard let image = UIImage(named: "pomeranian.jpeg") else {
            return
        }
        
        let birthday = Date(timeIntervalSinceNow: (-2 * 86500 * 380))
        
        let poodle = Dog(name: "poodle", birthday: birthday, breed: .poodle, image: image)
        
        
        //[3]viewModel
        let viewModel = DogViewModel(dog: poodle)
        viewModel.configure(dogView)
        
        
        self.view.addSubview(dogView)
        
        //layout
        dogView.translatesAutoresizingMaskIntoConstraints = false
        dogView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 135).isActive = true
        dogView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        dogView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 1).isActive = true
        dogView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -100).isActive = true
        
    }


}

 

 

 

MVVMTEST.zip
0.07MB

 

 

 

참고

https://lena-chamna.netlify.app/post/ios_design_pattern_mvvm/

https://gwangyonglee.tistory.com/49

https://lsh424.tistory.com/68