본문 바로가기
Swift/오류 개발자

Swift | presentingViewController.dismiss 오류(feat. 휴먼 에러)

by UDDT 2025. 3. 26.

 

징글징글한 관계 : 클래스와 인스턴스

 우리가 클래스에 대해 학습할때 매번 듣는 말이 있다.

"클래스는 인스턴스를 생성하고 쓰는 거라니까?"

"설계도만으로 제품의 행동에 접근할 수 없다니까?"

 

 머리로는 다 이해를 했는데, 코드를 보면 뇌가 멈춘다.

아마 while true로 무한루프 돌리는 듯...ㅠ

 

오늘의 과제

 오늘의 과제는 아래의 이미지처럼 구현하는 것이었다.

1. FirstView에 textLabel과 button이 있다.
2. button을 누르면 modalView로 넘어간다.
3. modalView에서 버튼을 누르면 이전 화면(FirstView)로 돌아간다.
4. 이전 화면의 textLabel이 바뀐다. 

 

 모두가 그렇지만 코드 작성은 아주 순조로웠다.

누구나 그럴싸한 계획이 있다. 쳐맞기 전까지는...

 

내가 작성한 코드

  코드베이스UI를 시작한 코린이.

 신이 나서 막 적어내려갔다.

// FirstViewController.swift
class FirstViewController: UIViewController {

    var comment = "First ViewController"

    let label = UILabel()
    let button = UIButton()

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewIsAppearing(_ animated: Bool) {
        super.viewIsAppearing(animated)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }

    private func configureUI() {
        view.backgroundColor = .brown

        label.text = "\(comment)"
        label.textAlignment = .center

        button.setTitle("First Button", for: .normal)
        button.backgroundColor = .black
        button.layer.cornerRadius = 8
        button.addTarget(self, action: #selector(presentModalView), for: .touchDown)

        [label, button].forEach { view.addSubview($0) }
        [label, button].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor),

            button.centerXAnchor.constraint(equalTo: label.centerXAnchor),
            button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
            button.widthAnchor.constraint(equalToConstant: 100)
        ])
    }

    @objc
    func changeText() {
        label.text = "나도 이제 코드베이스 UI한다~"
    }

    @objc
    private func presentModalView() {
        let modalViewController = ModalViewController()
        modalViewController.modalPresentationStyle = .fullScreen
        self.present(modalViewController, animated: true)
    }
}
class ModalViewController: UIViewController {

    let label = UILabel()
    let button = UIButton()

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewIsAppearing(_ animated: Bool) {
        super.viewIsAppearing(animated)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }

    private func configureUI() {
        view.backgroundColor = .gray

        label.text = "Modal ViewController"
        label.textAlignment = .center

        button.setTitle("First Button", for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.backgroundColor = .white
        button.layer.cornerRadius = 8
        button.addTarget(self, action: #selector(dismissModalView), for: .touchDown)

        [label, button].forEach { view.addSubview($0) }
        [label, button].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor),

            button.centerXAnchor.constraint(equalTo: label.centerXAnchor),
            button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
            button.widthAnchor.constraint(equalToConstant: 100)
        ])
    }

    @objc
    private func dismissModalView() {
        let firstViewController = FirstViewController()
        self.presentingViewController?.dismiss(animated: true, completion: firstViewController.changeText)
    }
}

 

  나 혹시 재능이 있을지도?

나 의외로 재능충인가?

  빌드 결과는 처참했다.

또 오류를 개발해벌임...

 

  야심차게 버튼을 눌렀지만 아무것도 바뀌지 않았다.

 

  오류개발자의 솜씨를 본 튜터님께서 나지막히 말씀하셨다.

  "오늘 배운 내용에 답이 있어요."

 

    금붕어입니까? 휴먼?

짤툰(금붕어 키우는 만화)

  

  약 15초간 얼 타고 있었다.

 

  캠프파이어의 불멍마냥 멍 때리고 있는 나를 보고 튜터님이 힌트를 주셨다

  "지금 그 FirstView가 메모리에 저장되어 있는 FirstView인가요?"

 

 

   점심시간, 군대 복도에서 냄새를 맡으면

  오늘 점심이 무슨 메뉴인지 알 수 있듯

  힌트를 통해 약간의 향기를 맡은 뒤 방향을 알 것만 같았다.

 

  몇차례의 실랑이 끝에 정답을 알 수 있었다.

 

트러블 슈팅

  1. 첫번째 실랑이

@objc
    private func dismissModalView() {
        let firstViewController = presentingViewController
        firstViewController?.dismiss(animated: true, completion: firstViewController.changeText)
    }
}

 

firstViewController에 presentingViewController를 넣어줬는데 왜 안될까?

 

 firstViewController를 확인해보면 Optional로 지정되어 있다. 있을 수도 있고 없을 수도 있는 값.

guard let으로 처리해주고 나니 다음 에러를 발견할 수 있었다.

 


  2. 두번째 실랑이

 

 UIViewController는 changeText라는 메서드를 가지고 있지 않다.

FirstViewController에 changeText 메서드를 구현해줬기 때문이다.

 

문제해결 : 타입 캐스팅  

   UIViewController를 어떻게 FirstViewController로 바꿔줄 수 있을까?

정답은 Type Casting이다.

@objc
    private func dismissModalView() {
        guard let firstViewController = presentingViewController as? FirstViewController else { return }
        firstViewController.dismiss(animated: true, completion: firstViewController.changeText)
    }
}

  

 

최종 작성 코드

// FirstViewController.swift
class FirstViewController: UIViewController {

    var comment = "First ViewController"

    let label = UILabel()
    let button = UIButton()

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewIsAppearing(_ animated: Bool) {
        super.viewIsAppearing(animated)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }

    private func configureUI() {
        view.backgroundColor = .brown

        label.text = "\(comment)"
        label.textAlignment = .center

        button.setTitle("First Button", for: .normal)
        button.backgroundColor = .black
        button.layer.cornerRadius = 8
        button.addTarget(self, action: #selector(presentModalView), for: .touchDown)

        [label, button].forEach { view.addSubview($0) }
        [label, button].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor),

            button.centerXAnchor.constraint(equalTo: label.centerXAnchor),
            button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
            button.widthAnchor.constraint(equalToConstant: 100)
        ])
    }

    @objc
    func changeText() {
        label.text = "나도 이제 코드베이스 UI한다~"
    }

    @objc
    private func presentModalView() {
        let modalViewController = ModalViewController()
        modalViewController.modalPresentationStyle = .fullScreen
        self.present(modalViewController, animated: true)
    }
}
// ModalViewController.swift
class ModalViewController: UIViewController {

    let label = UILabel()
    let button = UIButton()

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

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewIsAppearing(_ animated: Bool) {
        super.viewIsAppearing(animated)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
    }

    private func configureUI() {
        view.backgroundColor = .gray

        label.text = "Modal ViewController"
        label.textAlignment = .center

        button.setTitle("First Button", for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.backgroundColor = .white
        button.layer.cornerRadius = 8
        button.addTarget(self, action: #selector(dismissModalView), for: .touchDown)

        [label, button].forEach { view.addSubview($0) }
        [label, button].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor),

            button.centerXAnchor.constraint(equalTo: label.centerXAnchor),
            button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
            button.widthAnchor.constraint(equalToConstant: 100)
        ])
    }

    @objc
    private func dismissModalView() {
        guard let firstViewController = presentingViewController as? FirstViewController else { return }
        firstViewController.dismiss(animated: true, completion: firstViewController.changeText)
    }
}

 

최근댓글

최근글

skin by © 2024 ttuttak