Delegate라는 단어의 뜻에서 예측할 수 있듯이, 델리게이션 디자인 패턴은 하나의 객체가 다른 객체를 대신해 동작 또는 조정할 수 있는 기능을 제공 한다.
델리게이션 디자인 패턴은 Foundation, UIKit, AppKit 그리고 Cocoa Touch 등 애플의 프레임워크에서 광범위하게 활용하고 있으며 주로 프레임워크 객체가 위임을 요청 하고 (주로 애플리케이션 프로그래머가 작성하는)커스텀 컨트롤러 객체가 위임을 받아 특정 이벤트에 대한 기능을 구현 한다. 델리게이션 디자인 패턴은 커스텀 컨트롤러에서 세부 동작을 구현함으로써 동일한 동작에 대해 다양한 대응을 할 수 있게 해준다.
예로 UITextFieldDelegate를 살펴보자.
UITextFieldDelegate는UITextField의객체의문구를편집하거나관리하기위해아래와같은메서드를정의해두었다.// 대리자에게 특정 텍스트 필드의 문구를 편집해도 되는지 묻는 메서드functextFieldShouldBeginEditing(UITextField)// 대리자에게 특정 텍스트 필드의 문구가 편집되고 있음을 알리는 메서드functextFieldDidBeginEditing(UITextField)// 특정 텍스트 필드의 문구를 삭제하려고 할 때 대리자를 호출하는 메서드functextFieldShouldClear(UITextField)// 특정 텍스트 필드의 `Return` 키가 눌렸을 때 대리자를 호출하는 메서드functextFieldShouldReturn(UITextField)위메서드에서알수있듯이,델리게이트는특정상황에대리자에게메시지를전달하고그에적절한응답받기위한목적으로사용
데이터소스(DataSource)
델리게이트와 매우 비슷한 역할을 하는 데이터소스가 있다.
델리게이트가 사용자 인터페이스 제어에 관련된 권한을 위임받고
데이터소스는 데이터를 제어하는 기능을 위임받는다.
많이 사용되는 데이터소스에는 UITableViewDataSource와 UICollectionViewDataSource 가 있다.
프로토콜(Protocol)
코코아터치에서 프로토콜을 사용해 델리게이션과 데이터소스를 구현할 수 있다.
객체간 소통을 위한 강력한 통신 규약으로 데이터나 메시지를 전달할 때 사용하며, 프로토콜은 특별한 상황에 대한 역할을 정의하고 제시하지만 세부기능은 미리 구현해두지 않는다.
구조체, 클래스, 열거형에서 프로토콜을 채택하고 특정 기능을 수행하기 위한 요구사항을 구현할 수 있다.
importUIKitclassViewController:UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate{lazyvarimagePicker:UIImagePickerController={letpicker:UIImagePickerController=UIImagePickerController()picker.sourceType=.photoLibrarypicker.delegate=self// ViewController가 picker의 delegate 역할을 한다고 선언returnpicker}()@IBOutletweakvarimageView:UIImageView!@IBActionfunctouchUpSelectImageButton(_sender:UIButton){self.present(self.imagePicker,animated:true,completion:nil)funcimagePickerControllerDidCancel(_picker:UIImagePickerController){self.dismiss(animated:true,completion:nil)}funcimagePickerController(_picker:UIImagePickerController,didFinishPickingMediaWithInfoinfo:[UIImagePickerController.InfoKey:Any]){ifletoriginalImage:UIImage=info[UIImagePickerController.InfoKey.originalImage]as?UIImage{self.imageView.image=originalImage}self.dismiss(animated:true,completion:nil)}}
사실, 화면을 전환한다기 보다는 이목을 집중해야 하는 화면을 다른 화면 위로 띄워(Presenting) 표현하는 방식으로 모달로 보이는 화면을 사라지게 하려면 반드시 특정 선택을 해야한다는 특징이 있다. 예를 들어 얼럿을 통해 확인/취소 중 하나를 선택해야 한다거나 액션시트에서 무엇인가 선택을 해야하거나 또는 이메일이나 문자를 작성하는 화면에서는 전송완료 또는 취소 버튼을 통해서만 모달로 보이는 화면을 사라지게 만들 수 있다. 그래서 모달은 내비게이션 인터페이스와는 달리 정보의 흐름을 가지고 화면을 이동한다기 보다는 꼭 이목을 끌어야하는 화면에서 사용 한다. 내비게이션 인터페이스를 통해 화면을 표현하는 것과는 용도가 완전히 다르다고 볼 수 있으며, 모달로 보이는 화면은 되도록 단순하고 사용자가 빠르게 처리할 수 있는 내용을 표현하는 것이 좋다.
정보의 흐름이 아닌, 잠깐의 팝업 혹은 잠시간의 입력폼을 보여준다.
Presenting a View Controller
뷰 컨트롤러를 화면상에 나타내는 방법은 두 가지이다.
컨테이너뷰 컨트롤러에 임베드하거나
프레젠테이션을 통해서 나타낼 수 있다.
뷰 컨트롤러의 나타내기(present) 지원 기능은 UIViewController 클래스에 내장되어 있으며 모든 뷰 컨트롤러 객체에서 사용할 수 있다. 뷰 컨트롤러를 나타내면 원래 뷰 컨트롤러(나타내는 뷰 컨트롤러 - presenting view controller)와 새롭게 나타나는 뷰 컨트롤러(나타나는 뷰 컨트롤러 - presented view controller) 간의 관계가 생성된다. 이 관계는 뷰 컨트롤러 계층의 일부를 형성하며, 나타나는 뷰 컨트롤러(presented view controller)가 사라질(dismissed) 때까지 그대로 유지된다.
프레젠테이션 및 전환 프로세스(The Presentation and Transition Process)
뷰 컨트롤러의 프레젠테이션은 새로운 콘텐츠를 화면에 애니메이션으로 표시할 수 있는 쉽고 빠른 방법이다. UIKit에 내장된 프레젠테이션 기능은 내장 혹은 커스텀 애니메이션을 사용하여 새로운 뷰 컨트롤러를 표시할 수 있도록 한다. 내장 프레젠테이션과 애니메이션은 UIKit의 모든 작업을 처리하기 때문에 아주 적은 코드로도 가능하다. 또한, 약간의 추가 코드를 이용해 커스텀 프레젠테이션 및 애니메이션을 사용할 수 있으며, 뷰 컨트롤러 프레젠테이션은 프로그래밍 방식 또는 세그(segues)를 사용하여 구현할 수 있다.
프레젠테이션 스타일 (Presentation Style)
뷰 컨트롤러의 프레젠테이션 스타일에 따라 뷰 컨트롤러가 화면에 나타나는 모양이 달라진다.
UIKit은 특정한 모양과 의도를 가진 많은 표준 프레젠테이션 스타일을 정의하며 각자의 커스텀 프레젠테이션 스타일을 정의하는 것도 가능하다. 애플리케이션을 디자인할 때 자신의 의도를 가장 잘 반영할 수 있는 프레젠테이션 스타일을 선택하고, 이를 나타내는 뷰 컨트롤러의 modalPresentationStyle 프로퍼티 에 적절한 상수를 할당하면 된다.
전체화면 프레젠테이션 스타일 (Full-Screen Presentation Style)
전체화면 프레젠테이션 스타일은 화면 전체를 덮으며, 아래의(underlying) 기본 콘텐츠와 상호작용을 방지한다. 가로 모드인 환경에서는 전체화면 스타일 중 단 하나만이 기본 콘텐츠를 완전히 커버할 수 있다. 나머지 스타일은 뷰를 흐리게 하거나 투명도를 낮추어 기본 뷰 컨트롤러의 일부분을 보여줄 수도 있다.
다음은 가로 모드 환경에서 UIModalPresentationFullScreen, UIModalPresentationPageSheet, UIModalPresentationFormSheet 프레젠테이션 스타일을 보여준다.
Tip : 일반적으로, UIKit은 UIModalPresentationFullScreen 스타일을 사용하여 뷰 컨트롤러를 표시할 때, 전환 애니메이션이 끝난 후에 아래에 위치한 뷰 컨트롤러의 뷰는 화면에서 보이지 않는다. 그 대신, UIModalPresentationOverFullScreen 스타일을 지정하여 아래의 뷰가 완전히 보이지 않는 것을 막을 수 있다. 이러한 스타일을 사용하여 표시된 뷰 컨트롤러(presented view controller)에 투명한 구역을 만들어 기본 콘텐츠가 보이도록 할 수 있다.
팝오버 스타일 (The Popover Style)
UIModalPresentationPopover스타일은 뷰 컨트롤러를 팝오버뷰로 나타낸다. 팝오버는 추가 정보, 포커스(focused), 선택한 객체와 관련된 항목 목록을 표시하는 데 유용 하다. 프레젠테이션 스타일은 기본적으로 UIModalPresentationOverFullScreen으로 팝업 뷰 외부에 탭을 하게 되면 자동으로 팝업을 닫는다(dismiss).
UIModalPresentationCurrentContext 스타일은 아래 뷰 컨트롤러의 콘텐츠 영역에 콘텐츠를 올리는 형태
프레젠테이션 컨텍스트를 정의하는 뷰 컨트롤러는 프레젠테이션 중에 사용할 전환 애니메이션(transition animations)을 정의할 수도 있다. 일반적으로 UIKit은 나타난(presented) 뷰 컨트롤러의 modalTransitionStyle프로퍼티 값을 사용하여 뷰 컨트롤러를 애니메이션으로 화면 상에 나타낸다. 프레젠테이션 컨텍스트 뷰 컨트롤러(즉, 가려지는 뷰 컨트롤러)의 providesPresentationContextTransitionStyle이 true로 설정된 경우, UIKit은 나타나는 뷰 컨트롤러의 modalTransitionStyle프로퍼티 값 대신 가려지는 뷰 컨트롤러의 modalTransitionStyle 프로퍼티 값을 사용
다음은 가로 모드 환경에서 C 뷰 컨트롤러의 뷰가 A 뷰 컨트롤러 뷰의 콘텐츠 영역을 덮는 컨텍스트 스타일을 보여준다
커스텀 프레젠테이션 스타일 (Custom Presentation Styles)
UIModalPresentationCustom스타일을 사용하면 정의한 커스텀 스타일을 사용하여 뷰 컨트롤러를 표시할 수 있다.
커스텀 스타일을 생성하는 것은 UIPresentationController를 상속 받아 그 메서드를 사용하여 커스텀 뷰를 화면 상에 애니메이션으로 나타내고 표시된 뷰 컨트롤러의 크기와 위치를 설정하는 것이다. 커스텀 프레젠테이션 컨트롤러를 정의하는 것에 대한 자세한 정보는 커스텀 프레젠테이션 생성하기(Creating Custom Presentations) 를 참고
전환 스타일 (Transition Styles)
전환 스타일은 뷰 컨트롤러를 표시하는데 사용하는 애니메이션 유형을 결정
기본으로 제공하는 전환 스타일의 경우 표시할 뷰 컨트롤러의 modalTransitionStyle프로퍼티에 지정할 수 있으며 뷰 컨트롤러를 표시할 때, UIKit은 해당 스타일에 맞는 애니메이션을 생성한다.
UIModalTransitionStyleCoverVertical이 뷰 컨트롤러를 화면 상에서 어떻게 애니메이션으로 나타내는지를 알 수 있으며 뷰 컨트롤러 B는 화면 밖에서 시작해서 애니메이션을 통해 뷰 컨트롤러 A의 위쪽 상단까지 커버한다. 뷰 컨트롤러 B가 사라지면(dismissed) 애니메이션 또한 반전되어 B가 아래로 슬라이드되어 A가 드러나게 된다. 애니메이터 객체와 전환 델리게이트(transitioning delegate)를 사용하여 커스텀 전환 과정을 생성 할 수 있다. 커스텀 전환을 구현하는 방법에 대한 자세한 내용은 전환 애니메이션 커스터마이징(Customizing the Transition Animations)을 참고
아래는 표준 슬라이드 업 전환(standard slide-up transition) 그림이다.
뷰 컨트롤러를 나타내기 VS 보여주기(Presenting VS Showing a View Controller)
UIViewController 클래스는 뷰 컨트롤러를 표시하는 두가지 방법을 제공한다.
showViewController:sender:와 showDetailViewController:sender: > 해당 메서드는 뷰 컨트롤러를 표시하는 데에 가장 적응성이 우수하고 유연한 방법을 제공한다. 이 메서드를 사용하면 나타내는 뷰 컨트롤러(presenting view controller)가 프레젠테이션을 가장 잘 처리할 방법을 결정할 수 있다. 예를 들어, 컨테이너뷰 컨트롤러는 뷰 컨트롤러를 모달 방식으로 표시하는 대신, 이를 서브뷰로 통합할 수 있다. 기본 동작은 뷰 컨트롤러를 모달 방식으로 표시 합니다.
presentViewController:animated:completion: > 메서드는 뷰 컨트롤러를 항상 모달 방식으로 표시한다. 이 메서드를 호출하는 뷰 컨트롤러는 궁극적으로 프레젠테이션을 처리하지 못할 수도 있으나, 프레젠테이션은 항상 모달 방식을 채택하고 있다.
뷰 컨트롤러 표시하기(Presenting a View Controller)
뷰 컨트롤러의 프레젠테이션을 시작하는 방법은 여러 가지이다.
뷰 컨트롤러를 자동으로 표시하려면 세그(segue)를 사용!
세그: 인터페이스 빌더에서 지정한 정보를 사용하여 뷰 컨트롤러를 인스턴스화 하여 표시! 세그를 구성하는 방법에 관한 자세한 내용은 세그 사용하기(Using Segues) 를 참고!
showViewController:sender: 또는 showDetailViewController:sender:메서드를 사용!
커스텀뷰 컨트롤러의 경우, 이러한 메서드의 동작을 자신의 뷰 컨트롤러에 더욱 적합하도록 변경할 수 있다
presentViewController:animated:completion: 메서드를 호출하여 뷰 컨트롤러를 모달로 나타낼 수 있다
뷰 컨트롤러 보여주기(Showing View Controllers)
show(_:sender:) 와 showDetailViewController(_:sender:) 메서드를 사용할 때, 새로운 뷰 컨트롤러를 화면에 띄우는 과정은 간단하다.
나타나는 뷰 컨트롤러 객체를 만든다 > 뷰 컨트롤러를 생성할 때, 작업을 수행하는데 필요한 모든 데이터의 초기화는 각자의 책임이다.
새로운 뷰 컨트롤러의 modalPresentationStyle 프로퍼티를 선호하는 프레젠테이션 스타일로 설정
뷰 컨트롤러의 modalTransitionStyle 프로퍼티를 원하는 전환 애니메이션 스타일로 설정
현재 뷰 컨트롤러의 showViewController:sender: 와 showDetailViewController:sender: 메서드를 호출
UIKit은 showViewController:sender: 와 showDetailViewController:sender: 메서드에 대한 호출을 나타내는 뷰 컨트롤러(presenting view controller)에 전달한다. 그런 다음, 해당 뷰 컨트롤러는 프레젠테이션을 가장 효과적으로 수행할 방법을 결정하고, 필요할 경우 프레젠테이션 및 전환 스타일을 변경할 수 있다. 예를 들면, 내비게이션 컨트롤러가 뷰 컨트롤러를 내비게이션 스택(navigation stack)에 푸시(push)할 수 있다.
뷰 컨트롤러를 직접 나타내는 경우, UIKit에 새 뷰 컨트롤러를 표시하는 방법과 화면상에 애니메이션을 적용하는 방법을 알려준다.
나타나는 뷰 컨트롤러 객체를 만든다 > 뷰 컨트롤러를 생성할 때, 작업을 수행하는데 필요한 모든 데이터의 초기화는 각자의 책임이다.
새로운 뷰 컨트롤러의 modalPresentationStyle 프로퍼티를 선호하는 스타일로 설정
뷰 컨트롤러의 modalTransitionStyle 프로퍼티를 원하는 전환 애니메이션 스타일로 설정
현재 뷰 컨트롤러의 presentViewController:animated:completion: 메서드를 호출
present(_:animated:completion:) 메서드를 호출하는 뷰 컨트롤러는 모달 프레젠테이션 (modal presentation)을 실제로 수행하는 뷰 컨트롤러가 아닐 수도 있다. 프레젠테이션 스타일은 나타내는 뷰 컨트롤러에 필요한 특성을 포함하여, 뷰 컨트롤러가 나타나는 방식을 결정한다. 예를 들어, 전체화면 프레젠테이션은 전체화면 뷰 컨트롤러에서 시작해야 하며, 현재 표시된 뷰 컨트롤러가 적합하지 않은 경우에 UIKit은 적합한 뷰 컨트롤러를 찾을 때까지 뷰 컨트롤러 계층을 탐색해야한다. 모달 프레젠테이션이 완료되면 UIKit은 이에 영향을 받은 뷰 컨트롤러의 presentingViewController 및 presentViewController 프로퍼티를 업데이트한다.
팝오버에 뷰 컨트롤러 나타내기(Presenting a View Controller in a Popover)
팝오버를 나타내려면 추가적인 구성이 필요하다.
모달 프레젠테이션 스타일을 UIModalPresentationPopover로 설정한 후, 다음과 같은 팝오버 관련 속성을 구성할 수 있다.
뷰 컨트롤러의 preferredContentSize 프로퍼티를 이용해 원하는 크기로 설정할 수 있다.
뷰 컨트롤러의 popoverPresentationController 프로퍼티에서 접근할 수 있는 연관된 UIPopoverPresentationController 객체를 사용하여 팝오버 고정 점(popover anchor point)을 설정할 수 있다.
나타난 뷰 컨트롤러 닫기(Dismissing a Presented View Controller)
나타난 뷰 컨트롤러를 닫으려면 프레젠테이션 뷰 컨트롤러의 dismiss(animated:completion:) 메서드를 호출 혹은 제공된 뷰 컨트롤러 자체에서 이 메서드를 호출할 수도 있다.
표시된 뷰 컨트롤러에서 이 메서드를 호출하면 UIKit은 자동으로 이 요청을 나타내는 뷰 컨트롤러(presenting view controller)로 전달하며 뷰 컨트롤러를 닫기 전에 항상 중요한 정보를 저장해야한다. 뷰 컨트롤러를 닫으면 뷰 컨트롤러는 뷰 컨트롤러 계층에서 제거되며, 화면에서도 해당하는 뷰가 제거되기 때문이다. 별도로 저장된 강한 참조가 없는 경우, 뷰 컨트롤러를 닫으면 이와 연결된 뷰 컨트롤러가 메모리에서 해제(releases)된다.
다른 스토리보드에서 정의된 뷰 컨트롤러 나타내기(Presenting a View Controller Defined in a Different Storyboard)
하나의 스토리보드에 있는 뷰 컨트롤러 사이에는 세그를 생성할 수는 있으나, 스토리보드 간의 세그를 생성할 수 없다. 다른 스토리보드에 저장된 뷰 컨트롤러를 나타내고자 할 경우 다음과 같이 뷰 컨트롤러를 명시적으로 표시하기 전에 먼저 인스턴스화 해야한다. 예시에서는 뷰 컨트롤러를 모달로 나타내(presents)지만, 뷰 컨트롤러를 내비게이션 컨트롤러에 푸시하거나 다른 방법으로도 나타낼(display) 수 있다.
iOS에서 내비게이션 인터페이스는 주로 계층적 구조의 화면전환을 위해 사용되는 드릴 다운 인터페이스(drill-down interface) 이다. 드릴 다운 인터페이스란 아래 그림과 같이 각 선택할 수 있는 항목에 대한 세부항목이 존재하는 인터페이스를 의미한다. 내비게이션 인터페이스는 내비게이션 컨트롤러를 통해 구현 한다.
정보의 흐름, 깊이를 가진다.
내비게이션 컨트롤러
내비게이션 컨트롤러는 컨테이너 뷰 컨트롤러로써(container view controller) 내비게이션 스택(navigation stack)을 사용하여 다른 뷰 컨트롤러를 관리한다. 여기서 내비게이션 스택에 담겨서 콘텐츠를 보여주게 되는 뷰 컨트롤러들을 컨텐트 뷰 컨트롤러(content view controller) 라고 한다.
내비게이션 컨트롤러는 두 개의 뷰를 화면에 표시한다.
하나는 내비게이션 스택뷰에 포함된 최상위 컨텐트 뷰 컨트롤러의 콘텐츠를 나타내는 뷰
나머지는 내비게이션 컨트롤러가 직접 관리하는 뷰(내비게이션바 또는 툴바)
추가로 내비게이션 인터페이스의 변화에 따른 특정 액션을 동작하도록 하기 위해 내비게이션 델리게이트 객체 를 사용할 수 있다.
내비게이션 스택이란?
내비게이션 컨트롤러에 의해 관리되는 내비게이션 스택(Navigation stack)은 뷰 컨트롤러를 담을 수 있는 배열 과도 같다. 내비게이션 스택에 가장 하위에 있는(가장 먼저 스택에 추가된) 뷰 컨트롤러는 내비게이션 컨트롤러의 루트 뷰 컨트롤러(root view controller) 가 된다. 루트 뷰 컨트롤러는 내비게이션 스택에서 팝(pop)되지 않는다. 내비게이션 스택의 가장 상위에 있는(가장 마지막에 푸시(push) 된) 뷰 컨트롤러는 최상위 뷰 컨트롤러로 화면에 보이게 된다.
이름에서도 알 수 있듯이 내비게이션 스택은 푸시(push)/팝(pop)을 통하여 아이템(뷰 컨트롤러)을 관리한다. 새로운 뷰 컨트롤러를 내비게이션 스택에 푸시(push)하거나 내비게이션 스택에 있는 뷰 컨트롤러를 삭제하기 위해 팝(pop)을 사용하며, 내비게이션 스택에 푸시(push) 된 각 뷰 컨트롤러들은 애플리케이션에 자신이 가지고 있는 뷰 계층 구조를 통해 콘텐츠를 표시하게 된다.
내비게이션 스택에서의 화면이동
UINavigationController 클래스의 메서드 또는 세그(segue)를 사용하여 내비게이션 스택의 뷰 컨트롤러를 추가/삭제할 수 있다. 또한 애플리케이션 실행 중 사용자가 내비게이션 인터페이스의 뒤로가기(back) 버튼을 사용하거나 화면의 왼쪽 가장자리를 스와이프(swipe)하여 스택에 있는 최상위 뷰 컨트롤러를 삭제하고 그 아래에 가려져 있던 뷰 컨트롤러의 콘텐츠를 보여줄 수도 있다.
(세그(segue)는 스토리보드에서 한 화면에서 다른 화면으로의 전환을 의미한다. 세그도 내부적으로 UINavigationController 클래스의 메서드를 사용)
이해를 돕기 위한 간단한 예를 통해 내비게이션 스택의 상태에 따라 어떻게 화면이 이동하는지 보자.
내비게이션 스택의 푸시(push)
내비게이션 스택에 새로운 뷰 컨트롤러가 푸시 될 때 UIViewController 인스턴스가 생성되고 내비게이션 스택에 추가 된다.
1.가장 먼저 내비게이션 스택에 루트 뷰 컨트롤러만 들어가 있는 초기상태이다 (내비게이션 컨트롤러를 생성할 때 반드시 루트 뷰 컨트롤러가 설정되어 있어야 한다)
2.’뷰 컨트롤러1로 이동’이라는 버튼을 통해서 내비게이션 스택에 뷰 컨트롤러1을 푸시(push)!
뷰 컨트롤러1의 인스턴스가 생성되고 내비게이션 스택에 추가됨과 동시에 뷰 컨트롤러1이 최상위 뷰 컨트롤러로써 화면에 보이게 된다.
3.’뷰 컨트롤러2로 이동’이라는 버튼을 통해서 내비게이션 스택에 뷰 컨트롤러2도 푸시한다!
뷰 컨트롤러2의 인스턴스가 생성되고 내비게이션 스택에 추가되며 뷰 컨트롤러2가 최상위 뷰 컨트롤러로써 화면에 보이게 된다. 여기서 주목할 점은 새로운 뷰 컨트롤러가 추가될 때도 아래에 있는 뷰 컨트롤러들이(인스턴스) 삭제되지 않고 유지 되고 있다는 점이다.
내비게이션 스택의 팝(pop)
내비게이션 스택에 존재하는 뷰 컨트롤러가 팝 될 때 생성되었던 UIViewController의 인스턴스는 다른 곳에서 참조되고 있지 않다면 메모리에서 해제되고, 내비게이션 스택에서 삭제된다.
1.푸시 예제의 마지막 상태에서 상단 내비게이션바에 있는 뷰 컨트롤러1을(back button) 눌러서 뷰 컨트롤러2를 팝한다.
뷰 컨트롤러2가 내비게이션 스택에서 삭제되며 뷰 컨트롤러1이 다시 최상위 뷰 컨트롤러로써 화면에 보여지게 된다.
2.내비게이션바에서 루트 뷰 컨트롤러를(back button) 눌러서 뷰 컨트롤러1을 팝한다.
뷰 컨트롤러1이 메모리에서 해제되고 내비게이션 스택에서 삭제되며 루트 뷰 컨트롤러가 최상위 뷰 컨트롤러가 되고 화면에 보여지게 된다. 루트 뷰 컨트롤러는 내비게이션 스택에서 팝 되지 않으며 상단에 내비게이션바를 통해서도 루트 뷰 컨트롤러를 팝 하는 버튼이 따로 생성되어 있지 않은 것을 확인할 수 있다.
UINavigationController 클래스
위에서 설명한 내비게이션 컨트롤러와 내비게이션 스택의 동작들이 UINavigationController 클래스에서 어떻게 구현되어있는지 살펴본다.
내비게이션 컨트롤러의 생성
// 내비게이션 컨트롤러의 인스턴스를 생성하는 메서드// 매개변수로 내비게이션 스택의 가장 아래에 있는 루트 뷰 컨트롤러가 될 뷰 컨트롤러를 넘겨준다init(rootViewController:UIViewController)
내비게이션 스택의 뷰 컨트롤러에 대한 접근
// 내비게이션 스택에 있는 최상위 뷰 컨트롤러에 접근하기 위한 프로퍼티vartopViewController:UIViewController?// 현재 내비게이션 인터페이스에서 보이는 뷰와 관련된 뷰 컨트롤러에 접근하기 위한 프로퍼티varvisibleViewController:UIViewController?// 내비게이션 스택에 특정 뷰 컨트롤러에 접근하기 위한 프로퍼티(루트 뷰 컨트롤러의 인덱스는 0)varviewController:[UIViewController]
내비게이션 스택의 푸시와 팝에 관한 메서드
// 내비게이션 스택에 뷰 컨트롤러를 푸시// 푸시 된 뷰 컨트롤러는 최상위 뷰 컨트롤러로 화면에 표시된다funcpushViewController(UIViewController,animated:Bool)// 내비게이션 스택에 있는 최상위 뷰 컨트롤러를 팝// 최상위 뷰 컨트롤러 아래에 있던 뷰 컨트롤러의 콘텐츠가 화면에 표시된다funcpopViewController(animated:Bool)->UIViewController?// 내비게이션 스택에서 루트 뷰 컨트롤러를 제외한 모든 뷰 컨트롤러를 팝// 루트 뷰 컨트롤러가 최상위 뷰 컨트롤러가 된다// 삭제된 모든 뷰 컨트롤러의 배열이 반환funcpopToRootViewController(animated:Bool)->[UIViewController]?// 특정 뷰 컨트롤러가 내비게이션 스택에 최상위 뷰 컨트롤러가 되기 전까지 상위에 있는 뷰 컨트롤러들을 팝funcpopToViewController(_viewController:UIViewController,animated:Bool)->[UIViewController]?
내비게이션 인터페이스를 구성하는 두 가지 방법
스토리보드를 사용하여 내비게이션 인터페이스 구성하기
스토리보드에서 내비게이션 컨트롤러에 포함할 뷰 컨트롤러를 선택
메뉴에서 [Editor] - [Embed In] - [Navigation Controller]를 차례로 선택
선택한 뷰 컨트롤러가 내비게이션 컨트롤러의 루트 뷰 컨트롤러가 되면서 내비게이션 컨트롤러가 생성됨
위의 방법 외에도 객체 라이브러리에서 내비게이션 컨트롤러를 드로그 앤 드롭해서 캔버스에 올릴 경우 테이블 뷰를 포함한 루트 뷰 컨트롤러가 생성되면서 내비게이션 컨트롤러가 만들어짐
코드작성을 통해 내비게이션 인터페이스 구성하기
코드로 내비게이션 컨트롤러를 생성할 경우, 내비게이션 컨트롤러가 생성되기 원하는 적절한 지점에 내비게이션 컨트롤러를 생성할 수 있다. 예를 들어 내비게이션 컨트롤러가 애플리케이션 윈도우(window)의 루트 뷰로서 역할을 한다면, 내비게이션 컨트롤러를 applicationDidFinishLaunching: 메서드에 구현할 수 있다.
루트 뷰 컨트롤러가 될 뷰 컨트롤러를 생성 > 이 객체는 처음에 내비게이션 스택의 최상위 뷰 컨트롤러가 화면에 보이게 되고 내비게이션 바에 뒤로가기 버튼이 생성되지 않는다
init(rootViewController: UIViewController) 메서드를 통해 내비게이션 컨트롤러를 초기화하고 생성
내비게이션 컨트롤러를 윈도우의 루트 뷰 컨트롤러로 설정
funcapplication(_application:UIApplication,didFinishLaunchingWithOptionslaunchOptions:[UIApplicationLaunchOptionsKey:Any]?)->Bool{// Override point for customization after application launch.// 루트 뷰 컨트롤러가 될 뷰 컨트롤러를 생성letrootViewController=UIViewController()// 위에서 생성한 뷰 컨트롤러로 내비게이션 컨트롤러를 생성letnavigationController=UINavigationController(rootViewController:rootViewController)self.window=UIWindow(frame:UIScreen.main.bounds)// 윈도우의 루트 뷰 컨트롤러로 내비게이션 컨트롤러를 설정self.window?.rootViewController=navigationControllerself.window?.makeKeyAndVisible()returntrue}
내비게이션바의 구성
내비게이션바는 내비게이션 컨트롤러에 의해 생성 된다.
내비게이션바는 내비게이션 컨트롤러의 관리를 받는 모든 뷰 컨트롤러의 상단에 표시 되며 최상위 뷰 컨트롤러가 변경될 때마다 내비게이션 컨트롤러는 내비게이션바를 업데이트한다.
H.I.G 문서는 애플리케이션을 개발할 때 필요한 디자인과 동작을 포함한 여러 규칙을 통하여 사용자 인터페이스를 어떻게 구성하는 방법에 대한 지침을 제시한다. H.I.G 문서의 가이드라인을 따라 인터페이스를 작성하면 사용자들로 하여금 새로운 애플리케이션을 처음 접하더라도 대부분의 iOS 사용자에게 익숙한 환경을 제공할 수 있다. 좋은 인터페이스를 사용자에게 제공하는 것은 애플리케이션의 사용자를 더 많이 끌어들일 수 있는 하나의 포인트가 될 수 있다.
왜 H.I.G 문서를 읽어야하나?
애플리케이션을 설계할 때 사용자와 상호작용에 관해 생각하고 설계할 수 있다
개발자가 아닌 사용자의 입장에서 애플리케이션을 바라보고 설계할 수 있다
애플리케이션의 일관성을 유지할 수 있다
기획자, 디자이너 등 협업에 있어 기준점을 제시하여 협업의 효율을 높일 수 있다
이미 사용자에게 익숙한 환경을 제공하여 새로운 애플리케이션 사용의 진입장벽을 낮출 수 있다
이미 검증된 사용자 경험을 이해하고 그것을 토대로 조금 더 유연한 사용자 경험을 설계할 수 있다
H.I.G 문서는 프로그래머뿐만 아니라 디자이너, 기획자, 테스터 등 iOS 애플리케이션 개발에 참여하는 모든 사람이 읽어보는 것을 추천
H.I.G의 내용 구성
Overview
iOS 플랫폼 테마의 특징과 인터페이스 요소에 관한 개요
iOS의 버전이 업데이트 되면 새로운 iOS 버전의 특징과 변화에 관해서도 설명
App Architecture
애플리케이션 아키텍처 설계 시 고려해야 할 사항을 설명
User Interaction
애플리케이션이 사용자와 상호작용하는 동작 설계 시 고려해야 할 사항을 설명
System Capabilities
시스템이 지원하는 여러 시스템 기능과 각 기능에 대해 설계 시 고려해야 할 사항을 설명
Visual Design
애플리케이션의 시각적인 요소 설계 시 고려해야 할 사항을 설명
Icons and Images
iOS에서의 이미지, 아이콘, 시작화면에 관한 내용과 지침에 관한 내용을 설명
Bars
iOS에서 사용하는 바의 각 역할과 용도에 관한 설명과 각 바를 구현할 때 고려해야 할 사항에 관한 내용
Views
뷰의 종류와 역할에 관해 설명하고 뷰 설계 시 고려해야 할 사항에 관한 내용
Controls
여러 가지 컨트롤 요소들에 관한 소개와 설계 시 고려해야 할 사항들에 관한 내용
Extensions
여러 가지 확장기능을 소개하고 확장 기능을 사용하는 애플리케이션 설계 시 고려해야 할 사항들에 관해 설명
Technologies
여러 기술을 구현할 수 있는 Kit에 관해 설명하고 해당 Kit 사용 시 설계지침에 관한 내용