[TIL] 09.15

Junyoung_Hong·2023년 9월 15일
0

TIL_9월

목록 보기
12/19
post-thumbnail

1. MVC 패턴 적용하기

MVC 패턴은 비교적 많은 사람들이 사용하는 패턴이다. 이 패턴을 적용시킬 때, 가장 어려운 과정은 View와 Controller를 분리하는 과정이다. 앞으로 진행하는 과정들이 정답이 아닐 수 있지만, 적용시킨 과정을 기록하고자 한다.

우선 기존의 ViewController이다. 현재는 마땅한 Model이 필요없는 ViewController이기 때문에, View와 Controller를 분리하는것에 집중하고자 한다.

import UIKit
import SwiftUI
import SnapKit

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureUI()
        addSubView()
        autoLayout()
        buttonAction()
    }
    
    // Button 생성
    private lazy var profileDesignBtn: UIButton = {
       let button = UIButton()
        button.setTitle("ProfileDesginViewController", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        button.titleLabel?.font = .bold16
        return button
    }()
}

// UI 관련 extension
extension MainViewController {
    
    private func configureUI() {
        view.backgroundColor = UIColor.white
    }
    
    private func addSubView() {
        view.addSubview(profileDesignBtn)
    }
    
    private func autoLayout() {
        profileDesignBtn.snp.makeConstraints { make in
            make.centerX.equalTo(view.snp.centerX)
            make.centerY.equalTo(view.snp.centerY)
        }
    }
}

// 버튼 관련 extension
extension MainViewController {
    
    private func buttonAction() {
        profileDesignBtn.addTarget(self, action: #selector(moveProfileDesignVC), for: .touchUpInside)
    }
    
    @objc func moveProfileDesignVC() {
        let profileDesignVC = ProfileDesignViewController()
        profileDesignVC.modalTransitionStyle = .coverVertical
        profileDesignVC.modalPresentationStyle = .fullScreen
        self.present(profileDesignVC, animated: true, completion: nil)
    }
}

1-1. 새로운 View 만들기

정말 직관적으로 기존의 ViewController에 있는 View를 아예 외부에서 만든 View로 적용시키는 것이 전략이다. 기존의 VC에서 생성했던 버튼과 UI관련 Extension들을 View로 빼는것이다.

class MainView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        configureUI()
        addSubView()
        autoLayout()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // Button 생성
    private(set) lazy var profileDesignButton: UIButton = {
       let button = UIButton()
        button.setTitle("ProfileDesginViewController", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        button.titleLabel?.font = UIFont.bold16
        return button
    }()
}

private extension MainView {
    
    func configureUI() {
        backgroundColor = UIColor.white
    }
    
    func addSubView() {
        addSubview(profileDesignButton)
    }
    
    func autoLayout() {
        profileDesignButton.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.centerY.equalToSuperview()
        }
    }
}

이 때, 포인트는 버튼을 private(set) lazy var로 선언해준 부분이다.

private(set)

private(set)은 Swift에서 변수나 프로퍼티의 접근 제어 수준을 나타내는 방법 중 하나이다. 이것은 변수 또는 프로퍼티를 읽기 전용으로 만들고, 해당 변수 또는 프로퍼티의 값을 설정하는 것을 외부에서 금지하는 역할을 한다.

  1. private(set)을 사용하면 해당 변수 또는 프로퍼티를 정의한 스코프 내에서는 읽기 및 쓰기가 가능하다. 다시 말해, 변수 또는 프로퍼티의 값을 설정하는 것은 클래스나 구조체 내부에서 가능하다.

  2. 그러나 외부에서는 해당 변수 또는 프로퍼티의 값을 읽을 수만 있으며, 설정할 수는 없다. 즉, 읽기 전용으로 외부에서 접근이 제한된다.

lazy var

lazy var로 변수를 선언하는 이유는 해당 변수가 처음으로 필요할 때만 초기화되기 때문이다. 이는 성능 및 메모리 관리 측면에서 유용한 패턴 중 하나다.

lazy var를 사용하는 주요 이유:

  1. 지연 초기화: 변수가 처음으로 사용될 때까지 초기화가 지연된다. 이는 앱이 실행될 때 모든 변수를 한꺼번에 초기화하지 않고, 필요한 시점에 초기화하므로 초기 로딩 시간을 줄일 수 있다. 특히 초기화 비용이 높은 경우에 유용하다.

  2. 메모리 절약: lazy var는 처음 초기화될 때만 메모리를 할당하고 그 이전에는 메모리를 차지하지 않는다. 이는 앱이 메모리를 효율적으로 관리하는 데 도움이 된다.

  3. 복잡한 초기화 로직 분리: 변수가 복잡한 초기화 로직을 갖는 경우, 해당 로직을 lazy로 선언하여 다른 부분과 분리할 수 있다. 이로써 코드를 더 읽기 쉽게 만들고, 관련 코드를 하나의 블록으로 그룹화할 수 있다.

  4. 의존성 관리: 다른 프로퍼티나 객체에 의존하는 경우, lazy var를 사용하여 필요한 의존성이 해결된 후에 초기화할 수 있다.

private lazy var profileDesignButton의 경우 profileDesignButton이 처음 사용될 때만 초기화되므로, 앱 실행 초기에 필요하지 않은 메모리 및 연산 비용을 절약하는 데 도움이 된다. 이것은 효율적인 메모리 사용 및 성능 향상을 위해 사용하는 일반적인 패턴 중 하나이다.

1-2. Controller 정리하기

class MainViewController: UIViewController {
    
    private let mainView = MainView()
    
    override func loadView() {
        view = mainView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        buttonAction()
    }
}

// 버튼 관련 extension
private extension MainViewController {
    
    func buttonAction() {
        mainView.profileDesignButton.addTarget(self, action: #selector(moveProfileDesignVC), for: .touchUpInside)
    }
    
    @objc func moveProfileDesignVC() {
        let profileDesignVC = ProfileDesignViewController()
        profileDesignVC.modalTransitionStyle = .coverVertical
        profileDesignVC.modalPresentationStyle = .fullScreen
        self.present(profileDesignVC, animated: true, completion: nil)
    }
}

loadView()

loadView()는 UIViewController의 메서드로서, 컨트롤러의 뷰를 초기화하고 설정하는 역할을 한다. 이 메서드를 직접 오버라이드하여 컨트롤러의 뷰를 직접적으로 설정할 수 있다.

기본적으로 UIViewController는 뷰 컨트롤러가 처음으로 필요로 할 때(view 속성에 접근할 때) 자동으로 뷰를 생성하고 로드한다. 이 기본 동작은 대부분의 경우에 적합하지만, 때로는 사용자 정의 뷰를 사용하거나 특별한 초기화 로직을 수행해야 하는 경우가 있다. 이때 loadView() 메서드를 사용할 수 있다.

loadView() 메서드를 오버라이드하면, 뷰 컨트롤러의 뷰를 직접 생성하고 설정할 수 있다. 예를 들어, 프로그래밍 방식으로 뷰를 만들거나, 인터페이스 빌더에서 정의한 뷰를 로드하거나, 사용자 정의 뷰를 할당할 수 있다.

주의할 점은 loadView()를 오버라이드할 때는 반드시 뷰를 초기화해야 하며, view 속성에 할당해야 한다. 이 메서드에서 super.loadView()를 호출하지 않으면 view 속성이 nil로 유지되므로 주의가 필요히다.

MainViewController에서 loadView() 메서드를 오버라이드하여 mainView를 뷰로 설정하면, 기본 뷰 대신에 사용자 지정 뷰를 사용할 수 있게 되는 것이다.

profile
iOS 개발자를 향해 성장 중

0개의 댓글

관련 채용 정보