dismiss(animated:completion:)

  • iOS 개발을 하다보면 자주 사용하게 되는 메소드이다. present()로 띄운 UIViewController를 닫는다.
  • 애니메이션 유무와, 닫기 이후 불리는 completion을 받는다.

음…

  • 일단 이름부터 잘 와닿지 않는다. dismiss라고 하면 경찰 미드에서 미팅 끝났으니 해산!하는 느낌이었는데 창닫기라니. 안그래도 비영어권 화자인 나로서는 presentingViewControllerpresentedViewController가 헷갈린게 한두번이 아닌데 괜히 기분이 좀 그렇다.

이제 안까먹는다. 아래가 이다!

Responsible for?

  • Discussion을 살펴보면, 사실 이 메소드는 자기 자신을 닫는 메소드가 아니다. 보통 기능구현을 하면 아래 VC에서 뭔가 화면을 띄우고 싶으니까 present하고, 비즈니스 목적이 끝나면 올라온 VC에서 dismiss하도록 구현할텐데, 아래의 VC가 dismiss의 책임을 가지고 있고, 올라온 VC는 그저 아래의 VC에게 메시지를 전달하는 것 뿐이다.
  • 그럼 위의 그림에서 분홍색 VC에서 dismiss하면 흰색에 메시지를 전달하고, 분홍색을 띄운 책임을 가진 흰색이 분홍색을 화면에서 걷어낸다. 여기까지는 당연한 것 같다.
  • 그러면 흰색에서 dismiss하면 흰색을 띄운 책임을 가진 파랑색이 흰색을 닫는가?
 
import UIKit
 
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .systemBlue
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        self.present(WhiteViewController(), animated: true)
    }
}
 
class WhiteViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .white
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        self.present(PinkViewController(), animated: true) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
                self?.dismiss(animated: true)
            }
        }
    }
}
 
class PinkViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .systemPink
    }
}
 

안닫혀요

  • 아니다. 분홍색 VC만 사라지고 흰색 VC는 화면에 남아있는다. 여기서 혼란이 발생한다. 복잡한 앱 동선을 만들다 보면 분홍색VC가 자신을 닫았듯 나도 흰색 VC를 닫고 싶어서 dismiss했는데 왜…!
  • 동작하는게 마치 Responder Chain마냥 presentedVC를 닫는 이벤트를 처리할 수 있으면 실행하고, 그렇지 않으면 presentingVC에 요청하는 방식이라고 생각했다. 음…직관적이지는 않다.
  • 그럼 통일성을 위해 항상 presentingVC를 데려와서 닫는 함수를 만들어 쓰면 되겠네? 라고 잠깐 생각했는데, 만약 띄운 VC에서 직접 닫고 싶을 경우에는 self.presentedVC?.presentingVC?.dismiss() 꼴이 나서 이게 뭐하는건가 싶어 말았다. 프레임워크에 있는 메소드를 강제할 수 없기도 하고…흠
  • 그런데 이 괘씸한 이름을 가진 메소드는 나를 또 힘들게하는데…SwiftUI dismiss()에 대해