iOS : Navigation vs Modal (2)

Modal Present & Dismiss

Jay Kim
8 min readNov 7, 2021
Photo by Alvaro Reyes on Unsplash

오늘은 iOS 에서 화면을 전환할 때 사용하는 대표적인 두 가지 방법인

  • Navigation - Push & Pop
  • Modal - Present & Dismiss

중에서 Modal - Present & Dismiss 에 대해 이야기 해보려고 한다.
(Navigation - Push & Pop 에 대해서는 이전 글을 참고)

사실 iOS 개발하시는 분들이 늘상 사용하는 것들이기 때문에 뭘 이렇게 글로 쓰기까지 해야하나(?)라는 생각도 들긴 하지만, 실제로 Navigation, Modal 을 평소에 사용하면서도 그 특성이나 내부 동작에 대해 잘 모르고 있는 분들이 의외로 많다는 것을 알게 되어… 별 것 아니지만 알고 사용하면 큰 도움이 될 만한 내용들을 정리해보려고 한다.

1. Modal Present

우리가 평소에 Modal 방식으로 화면을 띄우기 위해 흔히 사용하는 present 함수는 아래와 같은 형태로 사용 가능하다.

present 함수

테스트를 진행하기 위해서 Present VC라는 title 을 가진 UIButton 을 만들어준다.
(그 외의 버튼들 및 이전 소스코드 확인이 필요하면 iOS : Navigation vs Modal (1) 를 참고해주세요 :-) )

“Present VC” 버튼을 추가

그리고 ViewController 코드는 다음과같이 작성해줍니다.

Present-VC 구현 코드

이제 코드를 실행해서 Present VC 동작을 실행하면 아래와 같이 동작하는 것을 확인할 수 있습니다.

Present VC 를 반복

2. Modal Dismiss

present 동작을 확인했으니 이제 화면에서 modal VC 를 제거하는 dismiss 함수에 대해 알아보자.
기본적으로는 특별할 것 없이 모두가 아는 것처럼 간단하게 animated 설정과, 필요할 경우 completion closure 를 전달하여 사용 가능하다.

dismiss 함수

그런데 여기서 정말 많은 개발자들이 간과하고 지나치는 것이 있는데, Apple 공식문서에서 아래 내용을 확인해보자.

Apple 공식 문서에서 dismiss 함수의 discussion

위의 red-box 내용이 무엇인고 하니,

  • A-VC 에서 present 를 호출하여 B-VC 가 화면에 나타났을 때
  • B-VC 에서 dismiss 를 호출하면 B-VC 는 A-VC 에게 해당 동작을 의뢰하고
  • A-VC 는 자신이 present 함수를 호출하여 화면에 나타났던, 자신의 presented-VC 인 B-VC 를 dismiss 시킨다.

는 내용이다.

일반적으로 VC 에서 dismiss 를 호출하면 VC 입장에서의 self 를 dismiss 시키는 것이라고 오해하는 경우가 많은데, dismiss 는 본질적으로 VC 가 present 시킨 presented-VC 를 dismiss 시키는 동작이다.
다만 dismiss 함수를 호출한 VC 입장에서 presented-VC 가 없는 경우, 자신의 presenting-VC 에게 해당 dismiss 를 처리하도록 전달하는 것이다.

이 차이를 이해하지 못하면 Modal-Stack 이 여러 개 쌓였을 때, Modal-Stack 내에서 특정 VC 를 선별하여 dismiss 시키는 코드를 작성할 수가 없다.

일단 Modal-Stack 내에서의 Presenting-VC, Presented-VC 의 관계에 대해서는 잠시 후에 더 설명하기로 하고, 일단 dismiss 동작을 구현해보자.

이 글의 초반에 공유했던 코드에 dismissViewController 라는 함수를 추가하고 버튼을 연결해주자.

“Dismiss VC” 버튼을 추가
dismissViewController 함수를 추가

이렇게 함수 추가 후에 버튼을 연결하고 실행시킨 후에, present 와 dismiss 를 반복해서 동작시키면 아래와 같이 동작하는 것을 확인할 수 있다.

Present, Dismiss 반복 실행

여기서 dismissViewController 함수의 내용을 다음과 같이 수정한 후에 다시 실행시켜 보자. 함수의 내용은 변경되었지만 실행 결과는 완전히 동일한 것을 확인할 수 있을 것이다.

dismissViewController 수정

3. VC-Relation on Modal-Stack

이제 우리가 present, dismiss 등을 실행할 때 ViewController 간의 어떤 관계가 생성되어 Modal-Stack 이 구성되는지 알아보자.

아래와 같이 VC 에서 present 를 두 번 호출하여 세 개의 VC 가 Modal-Stack 내에 있다고 가정했을 때

3-VCs Modal-Stack

3개의 ViewController 사이에는 다음과 같은 관계가 형성된다.

3-VCs Modal-Stack Relation

풀어서 설명하면

  • A-VC 에서 present 를 호출해서 B-VC 가 나타났을 때
  • A-VC 의 presentedViewController 는 B-VC 를 가리키고
  • B-VC 의 presentingViewController 는 A-VC 를 가리킨다.

UIKit 내부를 들여다보면 아래와 같이 UIViewController 내에 optional property 로 각각 정의되어 있는 것을 확인할 수 있고,

Apple 공식문서에서 presentedViewController, presentingViewController 을 찾아보면 아래와 같이 설명하고 있다.

presentedViewController
presentingViewController

또 이렇게 말로만 설명하면 아쉬우니, VC 가 나타나는 시점에 VC 관련된 정보들을 print 를 해보자.

printVCInfo 함수는 아래와 같이 구현되어 있고 viewDidAppear 시점에 다음과 같은 정보를 console 에 출력해준다.

  • 현재 VC 의 title
  • 현재 VC 의 navigaitonController 의 정보 (address)
  • 현재 VC 의 presentingViewController 정보 (address)
  • 현재 VC 의 presentingViewController 의 presentedViewController 의 정보 (address)
printVCInfo 함수

아래와 같이

  1. 앱 실행 후
  2. present 한 번
  3. dismiss 한 번

실행했을 경우

present 한 번, dismiss 한 번

console 에는 아래와 같이 print 되어있는 것을 확인할 수 있다.

console 에서 확인한 VC 정보

여기까지 데모를 진행했던 ViewController 의 전체 소스코드는 다음과 같다.

데모를 진행한 Full Sourece-Code

오늘은 iOS 의 화면전환 Flow 중 하나인 Modal Present & Dismiss 에 대해서 알아보았다.

여기까지 읽어주셔서 감사하고,
모든 iOS 개발자에게 행복 있기를~

--

--

Jay Kim

iOS를 사랑하는 Software Engineer, 반복 설명하는 것이 점점 귀찮아져서 글을 씁니다 ^^;;;;