"Build a view controller in storyboards, configure it with custom views, and fill those views with your app’s data."
스토리보드에 뷰 컨트롤러를 빌드하고, 커스텀 뷰와 함께 설정하며, 앱 데이터로 해당 뷰를 채웁니다.
MVC 디자인 패러다임에서 뷰 컨트롤러는 정보를 화면에 나타내는 뷰 객체와 앱 컨텐트를 저장하는 데이터 객체 사이를 맞춥니다. 구체적으로 뷰 컨트롤러는 뷰 계층구조와 뷰를 최신으로 유지하기 위해 필요한 상태 정보를 관리합니다. 모든 UIKit
앱은 컨텐트를 나타내기 위해 뷰 컨트롤러에 강하게 의존하며, 뷰와 UI 관련 로직을 관리하기 위해 커스텀 뷰 컨트롤러를 정의하게 될 것입니다.
생성하는 대부분의 커스텀 뷰 컨트롤러는 컨텐트 뷰 컨트롤러일 것입니다(즉 뷰 컨트롤러가 자신의 모든 뷰를 갖고 있고, 해당 뷰에 대한 상호작용을 관리합니다). 앱의 커스텀 컨텐트를 화면에 나타내기 위해 컨텐트 뷰 컨트롤러를 사용할 수 있으며, 커스텀 뷰로 데이터를 전달하거나 커스텀뷰로부터 데이터를 전달받는 데이터 전달 관리를 위해 뷰 컨트롤러 객체를 사용할 수 있습니다.
Note
컨텐트 뷰 컨트롤러와 반대로 컨테이너 뷰 컨트롤러는 다른 뷰 컨트롤러로부터 컨텐트를 뷰 계층구조로 통합합니다.UINavigationController
가 컨테이너 뷰 컨트롤러의 예시입니다. 컨테이너 뷰 컨트롤러 구현 방법에 대한 정보는 Implementing a Custom Container View Controller를 보시기 바랍니다.
Implementing a Custom Container View Controller
https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html#//apple_ref/doc/uid/TP40007457-CH11-SW12
https://velog.io/@panther222128/View-Controller-Definition#implementing-a-container-view-controller
컨텐트 뷰 컨트롤러를 정의하려면 UIViewController
서브클래싱부터 시작합니다. 인터페이스가 테이블 뷰 홋은 컬렉션 뷰를 포함하고 있다면 대신 UITableViewController
혹은 UICollectionViewController
를 서브클래싱 해야 합니다. 새 Xcode 프로젝트는 하나 혹은 하나 이상의 컨텐트 뷰 컨트롤러를 포함하고 있습니다. 수정이 가능하며 다른 무언가를 추가할 수 있습니다.
UIViewController
는 뷰 계층구조의 루트 뷰 역할을 한느 뷰 속성으로부터 접근 가능한 컨텐트 뷰를 포함합니다. 해당 루트 뷰로 인터페이스를 나타내기에 필요한 커스텀 뷰를 추가할 수 있습니다. 스토리보드에서 뷰 컨트롤러 씬으로 커스텀 뷰를 드래그해서 뷰를 추가할 수 있습니다. 예를 들어 아래 그림은 아이폰에서 이미지 뷰와 버튼을 갖는 뷰 컨트롤러를 보여줍니다.
뷰 컨트롤러에 뷰를 추가한 후 항상 해당 뷰의 크기 및 위치를 설정하기 위해 오토 레이아웃 제약을 추가해야 합니다. 제약은 뷰의 부모 혹은 형제뷰에 상대적인 크기 및 위치를 어떻게 할지 구체화하는 규칙이며, 제약은 다른 환경 및 기기에 자동으로 뷰가 적응할 수 있도록 해줍니다. 더 많은 정보는 View Layout을 보시기 바랍니다.
View Layout
https://developer.apple.com/documentation/uikit/view_layout
런타임 시점에 뷰 컨트롤러의 코드로부터 뷰에 접근할 필요가 있을 것입니다. 예를 들어 텍스트 뷰에서 텍스트를 가져오길 원할 수도 있고, 이미지 뷰에서 이미지를 변경시키길 원할 수도 있습니다. 이렇게 하려면 뷰 계층구조에서 뷰에 대한 참조가 필요합니다. 이러한 참조는 아웃렛을 사용해서 생성할 수 있습니다.
아웃렛은 IBOutlet
키워드를 포함하는, 뷰 컨트롤러에 있는 속성입니다. 이 키워드의 존재는 Xcode가 스토리보드에서 해당 속성을 드러낼 것을 알려줍니다. 아래 예시 코드는 두 가지 아웃렛에 대한 정의를 보여주고 있습니다. 스위프트에서 뷰 컨트롤러가 뷰에 두 번째 강한 참조를 갖지 않도록 weak
케워드를 포함시켜야 합니다(첫 번째는 뷰 계층구조 자신으로부터 기인합니다).
@IBOutlet weak var imageView : UIImageView?
@IBOutlet weak var button : UIButton?
Add an outlet connection to send a message to a UI object에서 설명하는 것처럼 스토리보드에서 각 아웃렛을 상응하는 뷰에 연결시켜야 합니다. 뷰 계층구조에서 모든 뷰에 대한 참조를 저장할 필요는 없습니다. 이후에 수정하게 될 뷰에 대한 참조만 저장하시기 바랍니다.
Add an outlet connection to send a message to a UI object
https://help.apple.com/xcode/mac/current/#/devc06f7ee11
뷰 컨트롤러를 인스턴스화 할 때 UIKit
은 스토리보드에서 설정한 모든 아웃렛을 재연결합니다. UIKit
은 뷰 컨트롤러의 viewDidLoad()
메소드 호출 전에 이러한 연결을 다시 설정합니다. 그렇기 때문에 이 메소드에서 해당 속성의 객체에 접근할 수 있습니다. 뷰를 코드 작성으로 생성하는 경우 뷰 컨트롤러의 적합한 속성에 명시적으로 뷰를 할당해줘야 합니다.
컨트롤은 사용자 상호작용을 알리기 위해 타깃 액션 디자인 패턴을 사용하며, 몇 가지 뷰는 변경사항에 대한 응답으로 노티피케이션을 포스트하거나 딜리게이트 메소드를 호출합니다. 뷰 컨트롤러는 이러한 상호작용에 대해 알아야 할 필요가 있으며, 이를 통해 뷰를 업데이트 합니다. 그리고 이렇게 할 수 잇는 몇 가지 방법이 있습니다.
컨트롤에 대한 사용자 상호작용에 응답하려면 아래 코드 리스트에서 보이는 시그니처 중 한 가지와 함께 액션 메소드를 정의해야 합니다. 메소드 정의에서 UIControl
에 대한 제너릭 레퍼런스를 더 구체적인 컨트롤 클래스로 교체하면 됩니다.
@IBAction func doSomething()
@IBAction func doSomething(sender: UIControl)
@IBAction func doSomething(sender: UIControl, forEvent event: UIEvent)
타깃 액션 디자인 패턴과 컨트롤 관련 이벤트 처리 방법에 대한 더 많은 정보는 UIControl
을 보시기 바랍니다.
UIControl
https://developer.apple.com/documentation/uikit/uicontrol
https://velog.io/@panther222128/UIControl
UIKit
은 뷰를 화면에 표시하기 전에 뷰 컨트롤러 및 뷰를 설정할 수 있는 몇 가지 기회를 줍니다. 스토리보드로부터 뷰 컨트롤러를 인스턴스화 할 때 UIKit
은 이 객체의 init(coder:)
메소를 호출해서 객체를 생성합니다.
Note
뷰 컨트롤러의 커스텀 초기화가 코더 객체가 제공할 수 있는 것을 넘어서면UIStoryboard
의instantiateInitialViewController(creator:)
메소드를 사용해서 코드 작성을 통해 이를 인스턴스화할 수 있습니다. 이 메소드는 블록과UIKit
이 제공하는 코더 객체를 사용해 뷰 컨트롤러를 직접 생성할 수 있게 해줍니다. 이 옵션은 뷰 컨트롤러가 요구하는 커스텀 데이터를 갖는 뷰 컨트롤러 초기화를 가능하게 하고, 스토리보드에서 뷰 및 다른 객체의 설정을 복구할 수도 있습니다.
뷰 컨트롤러를 화면에 나타낼 때 UIKit
은 처음으로 로드하고, 아래 단계의 연속을 사용하는 뷰를 설정합니다.
init(coder:)
메소드를 사용해서 각 뷰를 생성합니다.awakeFromNib()
메소드를 호출합니다.viewDidLoad()
메소드를 호출합니다.로드 시점에 뷰 컨트롤러 준비에 필요한 one-time 설정 단계만을 수행합니다. 스토리보드의 부분이 아닌 추가적인 뷰를 생성하고 설정하려면 로드 타임을 사용하시기 바랍니다. 뷰 컨트롤러가 스크린에 나타날 때마다 발생해야 하는 작업을 수행하지 않아야 합니다. 예를 들어 애니메이션을 시작하거나 뷰의 값을 업데이트하지 않아야 합니다.
뷰가 스크린에 나타나기 전에 모든 마지막 뷰 관련 작업을 짧게 수행해야 합니다. UIKit
은 뷰가 스크린에 나타날 준비가 되었을 때 가지고 있는 뷰 컨트롤러에게 알리고, 현재 환경에 맞추기 위해 해당하는 뷰의 레이아웃을 업데이트합니다. 아래 메소드를 순서대로 호출하면서 이뤄집니다.
viewWillAppear(_:)
메소드를 호출합니다.viewLayoutMarginsDidChange()
메소드를 호출합니다.viewSafeAreaInsetsDidChange()
메소드를 호출합니다.viewWillLayoutSubviews()
메소드를 호출합니다.viewDidLayoutSubviews()
메소드를 호출합니다.viewDidAppear(_:)
메소드를 호출합니다.뷰 컨트롤러의 viewWillAppear(_:)
메소드에서 뷰의 컨텐트를 업데이트할 수 있습니다. 여러 뷰의 컨텐트를 변경하는 것은 자동 레이아웃 업데이트를 트리거합니다. 그렇기 때문에 이 메소드에 변경사항을 만드는 것은 추가적인 레이아웃 단계를 피합니다. 변경사항을 만들 때 현재 환경에 대한 정보(디스플레이 스케일 혹은 수평과 수직 사이즈 클래스와 같은)에 접근하기 위해 뷰 컨트롤러의 traitCollection
속성을 사용할 것입니다. viewWillAppear(_:)
보다 빠르게 특성에 접근할 수 있을지라도 특성은 해당 메소드까지 완료될 것이라는 보장은 없습니다. iOS 12 및 이전 버너에서 UIKit
은 로드 타임 시점에 특성의 부분 집합만을 제공하며, viewWillAppear(_:)
메소드 전까지 특성으 ㅣ완전한 집합을 제공하지 않습니다. 사용 가능한 특성에 대한 더 많은 정보는 UITraitCollection
을 보시기 바랍니다.
UITraitCollection
https://developer.apple.com/documentation/uikit/uitraitcollection
https://velog.io/@panther222128/UITraitCollection
다른 테크닉을 사용해서 뷰 컨트롤러를 표시합니다. 그리고 뷰 컨트롤러 사이에 전환이 진행되는 동안 데이터를 전달합니다.
https://developer.apple.com/documentation/uikit/view_controllers/showing_and_hiding_view_controllers
https://velog.io/@panther222128/Showing-and-Hiding-View-Controllers
UIKit 앱의 뷰 계층구조를 관리하는 객체입니다.
https://developer.apple.com/documentation/uikit/uiviewcontroller
https://velog.io/@panther222128/ViewController
테이블 뷰 관리에 특화된 뷰 컨트롤러입니다.
https://developer.apple.com/documentation/uikit/uitableviewcontroller
https://velog.io/@panther222128/UITableViewController
컬렉션 뷰 관리에 특화된 뷰 컨트롤러입니다.
https://developer.apple.com/documentation/uikit/uicollectionviewcontroller
https://velog.io/@panther222128/UICollectionViewController