[iOS] viewController에서 view를 분리해 보자

·2024년 6월 17일

MVVM에 대해 깊게 파보기 전 내가 아는 MVC에 대해 돌아볼 필요성을 느꼈다.

거의 대부분 view를 그리는 코드와 viewController의 역할을 하는 코드를 모두 viewController에 작성하여 viewController 코드의 길이가 거대해지는 걸 보며 찝찝함을 버릴 수가 없었다 😥
(아무리 apple의 mvc에서 view와 viewController가 붙어 있다고 해도……)

따라서 view를 그리는 코드라도 분리하면,
vc가 massive해지는 걸 막을 수 있지 않을까 해서 viewController와 view의 분리에 대해 찾아봤다.

실제로 loadView()를 통해 viewController의 view를 내가 만든 view로 변경할 수 있었다.



loadView()

Creates the view that the controller manages.

  • controller가 관리하는 뷰를 만든다
  • 프로그래머들은 이 메서드를 직접 호출해서는 안 된다.
    호출하지 말라는 것은 self.loadView()를 부르지 말란 뜻이다. 프로그래머가 정의하지 말라는 것은 아니다.
  • 우리는 loadView()를 통해 뷰를 로드하거나 만들어 view 프로퍼티에 할당할 수 있다.
  • Interface builder을 사용하는 경우 메서드를 override하면 안 된다. (@IBOutlet)
  • 하지만 view를 직접 제작하는 경우에는 override가 가능하다.
    이때는 우리가 만든 view의 root view를 view 프로퍼티에 할당하면 된다.
  • loadView()를 직접 구현했다면 super을 호출하면 안 된다.


📌 간단 정리

loadView()를 통해 viewController의 view에 내가 만든 view를 할당해 주면 된다.

후에 viewController은 model과 view 사이의 역할을 하는 코드와 view의 lifecycle을 관리하는 코드, 여러 action 등 viewController에 알맞은 역할을 하면 된다.


아주 간단한 예시를 만들어 보았다.


  • viewController에 view를 같이 작성한 코드
import UIKit
import SnapKit
import Then

class ViewController: UIViewController {
    private let nameLabel = UILabel()
    private let descriptionLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

        setUI()
        setLayout()
    }

    private func setLayout() {
        [nameLabel, descriptionLabel].forEach {
            view.addSubview($0)
        }

        nameLabel.snp.makeConstraints {
            $0.center.equalToSuperview()
        }

        descriptionLabel.snp.makeConstraints {
            $0.centerX.equalTo(nameLabel)
            $0.top.equalTo(nameLabel.snp.bottom).offset(20)
        }
    }

    private func setUI() {
        view.backgroundColor = .white
        
        nameLabel.do {
            $0.text = "밍김"
            $0.font = .systemFont(ofSize: 30, weight: .bold)
        }
        
        descriptionLabel.do {
            $0.text = """
                    안녕하세요 iOS 개발자 밍김입니다.\\n저는 25살입니다.\\n잘 부탁드립니다."""
            $0.numberOfLines = 0
            $0.textAlignment = .center
        }
    }
}
  • viewController와 view 분리한 코드

view

import UIKit
import SnapKit
import Then

class SampleView: UIView {

    private let nameLabel = UILabel()
    private let descriptionLabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setUp()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setUp() {
        setLayout()
        setUI()
    }

    private func setLayout() {
        [nameLabel, descriptionLabel].forEach {
            self.addSubview($0)
        }

        nameLabel.snp.makeConstraints {
            $0.center.equalToSuperview()
        }

        descriptionLabel.snp.makeConstraints {
            $0.centerX.equalTo(nameLabel)
            $0.top.equalTo(nameLabel.snp.bottom).offset(20)
        }
    }

    private func setUI() {
        self.backgroundColor = .white

        nameLabel.do {
            $0.text = "밍김"
            $0.font = .systemFont(ofSize: 30, weight: .bold)
        }

        descriptionLabel.do {
            $0.text = """
                    안녕하세요 iOS 개발자 밍김입니다.\\n저는 25살입니다.\\n잘 부탁드립니다 ✨
                    """
            $0.numberOfLines = 0
            $0.textAlignment = .center
        }
    }
}

viewController

import UIKit

class SampleViewController: UIViewController {

   private var customView = SampleView()

   override func viewDidLoad() {
       super.viewDidLoad()
   }

   override func loadView() {
       self.view = customView
   }
}

필요한 경우 viewController에서 customView에 접근하여 customView의 여러 속성들을 사용하면 된다.




Reference

https://github.com/jeongju9216/DesignPattern/blob/main/MVC/MVC/MVC/Views/View.swift
https://www.hackingwithswift.com/articles/89/how-to-move-view-code-out-of-your-view-controllers

0개의 댓글