📌 경민 질문 답변 --- ## 1. 오토레이아웃은 bounds를 다루는 걸까요? frame을 다루는 걸까요? - 오토레이아웃을 통한 제약을 기준으로 frame의 좌표와 크기를 결정함 ### iOS 화면 체계에서 bounds 와 frame의 차이를 설명해주세요 - frame은 슈퍼 뷰 좌표계 기준으로 자신의 위치와 크기를 나타내고 bounds는 자신의 좌표계 기준으로 자신의 위치와 크기를 나타낸다. ### bounds를 활용해본 경험이 있나요? bounds는 언제 활용해볼 수 있을까요? - frame으로 뷰의 위치를 잡아야하는 경우 슈퍼뷰의 bounds를 기준으로 잡을 수 있다. ### 오토레이아웃과 frame의 차이에 대해 설명해주세요 - frame은 슈퍼 뷰의 좌표계에서 뷰의 원점, 높이, 너비를 정의한다. UI 배치를 위해 뷰 계층 구조의 모든 뷰에 대한 크기와 위치를 계산해야 한다. 화면 회전 등의 변경 사항이 생기면 영향을 받는 모든 뷰에 대해 프레임을 다시 계산해야 한다. 하지만 직접 위치를 잡기 때문에 성능은 좋다. - 오토레이아웃은 constraint를 통해 각 뷰의 크기와 위치를 계산한다. 이는 내부 및 외부 변경 사항 모두에 동적으로 대응하는 레이아웃을 생성한다. constraint는 두 뷰 간의 관계를 나타낸다. ### Intrinsic content size에 대해 설명해주세요 - 뷰의 현재 컨텐츠를 기반으로 크기가 정해진다. 레이블, 버튼 등은 표시되는 텍스트 양과 글꼴에 따라 결정되고 이미지 뷰는 이미지의 크기로 결정된다. ### CHCR에 대해 설명해주세요 - content hugging priority는 뷰가 늘어나지 않기 위한 우선 순위 - compression resistance priority는 뷰가 줄어들지 않기 위한 우선 순위 ### Superview와 Safe Area에 제약을 줄 때 각각의 차이점을 설명해주세요 - Safe Area에 제약을 줄 때는 뷰가 디바이스의 안전한 표시 영역 내에서 레이아웃됨 - 뷰의 상위 컨테이너로서 Superview에 제약을 줄 때는 해당 뷰가 Safe Area를 고려하지 않고 전체 Superview에 대한 레이아웃을 설정함 ## 2. Convenience init에 대해 설명해주세요 - 클래스를 위한 이니셜라이저. 일부 파라미터에 기본 값을 사용하여 designated 이니셜라이저를 호출한다. 특정 유즈케이스나 인풋값을 위해 만들 수도 있다. 공통 초기화 패턴에 대한 시간을 절약하거나 클래스 초기화 의도를 더 명확하게 만들 때 사용한다. ### Convenience init은 구조체에서 사용할 수 있나요? - convenience init은 클래스를 위한 이니셜라이저이기 때문에 값 타입에서 사용할 수 없다. ### 왜 구조체에서 사용할 수 없나요? - convenience init은 클래스를 위한 이니셜라이저이기 때문에 값 타입에서 사용할 수 없다. 구조체는 이니셜라이저를 designated와 convenience로 나누지 않는다. ### Convenience init이 필요한 이유가 무엇인가요? - 공통 초기화 패턴에 대한 시간을 절약하거나 클래스 초기화 의도를 더 명확하게 만들 때 사용한다. ### Memberwise init에 대해 설명해주세요 - struct는 사용자 정의 이니셜라이저를 정의하지 않은 경우 자동으로 모든 프로퍼티를 초기화할 수 있는 이니셜라이저를 받는다. ### default init에 대해 설명해주세요 - class든 struct든 모든 프로퍼티에 기본값이 있고 이니셜라이저가 정의되어 있지 않은 경우 디폴트 이니셜라이저를 제공한다(init()) ### 이니셜라이저 delegation rule(위임 호출) 3가지에 대해 설명해주세요 - 1. designated 이니셜라이저는 슈퍼 클래스의 designated 이니셜라이저를 호출해야 한다. - 2. convenience 이니셜라이저는 같은 클래스 내의 다른 이니셜라이저를 호출해야 한다. - 3. convenience 이니셜라이저는 궁극적으로 designated 이니셜라이저를 호출해야 한다. ### Failable Initializer(옵셔널 이니셜라이저)에 대해 설명해주세요 - 이니셜라이저가 초기화를 실패할 수 있는 경우에 사용됩니다. 초기화에 실패하면 nil을 반환하며, 성공하면 옵셔널 값이나 일반 객체를 반환합니다. 이를 통해 초기화 과정에서 오류가 발생할 수 있는 상황에서 안전하게 처리할 수 있습니다. --- 📌 맥스 질문 답변 --- ![](https://hackmd.io/_uploads/r1hxQz3-6.png) ## iOS 앱의 상태 변화에 따라 호출되는 메서드 종류에 대해 설명해주세요. ### 앱 실행 상태 변화시 호출되는 UIApplicationDelegate 메서드 |~iOS 12|iOS 13 ~| |:-:|:-:| |<img src="https://docs-assets.developer.apple.com/published/64a2e0dab8/app-state@2x.png" width="400">|<img src="https://docs-assets.developer.apple.com/published/c834d5ac04/scene-state@2x.png" width="400">| #### 앱 초기화 관련 활용 메서드 (참고 링크: [UIApplicationDelegate](https://developer.apple.com/documentation/uikit/uiapplicationdelegate)) - `application(_: willFinishLaunchingWithOptions:)` - 앱이 구동되어 필요한 초기 실행 과정이 완료되기 직전 호출되는 메서드 - 앱을 초기화하고 실행할 준비를 하는 데 필요한 처리 - `application(_: didFinishLaunchingWithOptions:)` - 앱이 사용자에게 화면으로 표시되기 직전에 호출되는 메서드 - 앱이 실행된 후 진행할 커스터마이징 또는 초기화 코드 작성 - *iOS 12까지는 이 메서드를 통해 UIWindow 개체를 구성하고 ViewController 인스턴스를 할당했었음 -> SceneDelegate로 이동됨* #### 앱 생명주기 관련 이벤트 메서드 - `applicationDidBecomeActive(_:)` - 실행된 앱이 전면(Foreground)에 표시될 때 호출되는 메서드 - 앱이 Inactive 상태에 들어가면서 일이 중지된 작업이 있다면 재시작하는 코드를 여기에 작성해야 함(예: 타이머나 스톱워치는 Inactive 상태에서는 화면 갱신이 이루어지지 않음) - `applicationWillResignActive(_:)` - 앱이 백그라운드로 이동 중에 호출되는 메서드 - 일시정지, 타이머 비활성화 등의 코드 작성 - `applicationWillEnterForeground(_:)` - 앱이 전면(Foreground)으로 올라올 때 호출되는 메서드 - API를 통한 앱 상태 갱신시 사용 - `applicationDidEnterBackground(_:)` - 앱이 백그라운드 상태에 진입했을 때 호출되는 메서드 - 즉 미래 어느 순간에 앱이 종료된다는 의미 -> 공유 자원 해제 처리 & 사용자 데이터 및 다시 실행될 때 현재 상태를 복구할 수 있도록 필요한 상태 정보 저장 처리 - `applicationWillTerminate(_:)` - 앱이 종료되기 직전에 호출되는 메서드 - 사용자 데이터 등을 종료 전에 한 번 더 저장 <br><details> <summary>기타 환경 변화에 따른 이벤트 메서드</summary> <div markdown="1"> #### 환경이 바뀔 때 실행되는 메서드 - `applicationProtectedDataDidBecomeAvailable(_:)` - 보호된 파일이 사용할 수 있게 되었음을 알림 - `applicationProtectedDataWillBecomeUnavailable(_:)` - 보호된 파일이 사용할 수 없어질 예정임을 알림 - `applicationDidReceiveMemoryWarning(_:)` - 앱이 시스템 메모리 경고를 받았음을 알림 - `applicationSignificantTimeChange(_:)` - 시간에 큰 변화가 생겼음을 알림 #### Background에서 데이터를 다운로드할 때 - `application(_:, handleEventsForBackgroundURLSession:, completionHandler:)` - URL 세션과 관련된 이벤트가 처리되기를 기다리고 있다고 알림 ... </div> </details> <br> ### 앱 실행 상태 변화시 호출되는 UISceneDelegate 메서드 #### Scene 연결 및 연결 해제 - `scene(_:willConnectTo:options:)` - 새로운 UI 인스턴스가 생성되거나 복원될 때 호출됨 - 이 메서드에서 해당 Scene과 관련된 UI 구성, 초기화 작업을 수행 - `sceneDidDisconnect(_:)` - Scene이 메모리에서 제거되기 전 호출됨 - Scene이 더 이상 사용되지 않을 때 정리 작업을 수행 #### Foreground로 전환 중 - `sceneWillEnterForeground(_:)` - Scene이 Foreground로 이동하기 전에 호출됨 - 앱 상태를 갱신하거나 데이터를 업데이트하는 작업에 사용 - 메서드 뒤에 항상 `sceneDidBecomeActive(_:)`를 호출 - `sceneDidBecomeActive(_:)` - Scene이 활성화되어 사용자에게 보이기 전에 호출됨 - View 내용을 새로 고치거나, 타이머를 시작하거나, UI의 프레임 속도를 높일 수 있음 #### Background로 전환 중 - `sceneWillResignActive(_:)` - Scene이 비활성화되어 백그라운드로 이동하기 직전 호출됨 - 사용자와의 상호작용을 중지하도록 준비 - 일시 중지, 타이머 비활성화 등을 수행하는 코드 작성 - Scene에 저장되지 않은 데이터가 있는 경우 해당 데이터가 손실되지 않도록 저장하는 방법 중 하나 - `sceneDidEnterBackground(_:)` - Scene이 백그라운드로 이동할 때 호출됨 - Scene의 메모리 사용량을 줄이고 공유 리소스를 확보함 - 메서드 반환 후 App Swicher에 표시하기 위해 Scene 인터페이스 스냅샷을 찍음 - 스냅샷에 민감한 사용자 정보가 포함되어있지 않은지 확인 필요 <br><details> <summary>기타 환경 변화에 따른 이벤트 메서드</summary> <div markdown="1"> #### URL을 여는 중 - `scene(_:openURLContexts:)` - Scene API를 통해 URL을 열도록 요청하는 메서드로 여러 뷰 컨트롤러를 관리하는 데 사용됨. - 앱이 URL을 열 때 호출되고 주로 앱 내에서 다른 컨텐츠로 이동하거나 외부 앱과 상호작용할 때 사용됨. #### 지속적인 사용자 활동 - `scene(_:willContinueUserActivityWithType:)` - 지정된 유형의 활동 처리를 준비하기 위해 호출 - 메서드 반환 후 Scene이 활동을 처리하고 있다는 피드백을 사용자에게 제공함 - `scene(_:continue:)` - 제공된 활동 객체의 데이터로 지정된 Scene을 업데이트하기 위해 호출 - 다른 기기에서 발생할 수 있는 활동 객체에 대한 모든 데이터를 수신한 후에만 앱의 메인 스레드에서 이 메서드를 호출 - `scene(_:didFailToContinueUserActivityWithType:error:)` - 지정된 활동을 완료할 수 없음을 사용자에게 알리기 위해 호출 - 이 메서드를 구현하지 않으면 UIKit은 실패 이유에 대한 적절한 메시지와 함께 사용자에게 오류를 표시함 #### Scene의 상태 저장 - `stateRestorationActivity(for:)` - Scene의 현재 상태에 대한 정보가 포함된 NSUserActivity 개체를 반환하기 위해 호출 - Scene의 연결을 끊었다가 다시 연결한 후 해당 상태를 다시 복원할 수 있도록 충분한 정보를 저장해야 함 - `scene(_:restoreInteractionStateWith:)` - `scene(_:didUpdate:)` - 지정된 사용자 활동 개체에 최종 데이터를 추가하기위해 호출 </div> </details> <br> ## App Delegate와 Scene Delegate의 역할 차이는 무엇인가요? - App Delegate - App 자체의(Process) Life Cycle 및 설정 관리 - 앱의 시작/종료 포함 애플리케이션 수준의 이벤트 처리 - 푸시 알림 등록, 위치 서비스 등의 외부 서비스 처리 가능 - Session의 Life Cycle 관리 - Scene Session을 통해 Scene에 대한 정보를 받아서 해당 사이클을 관리함 - application(_ : configurationForConnecting: options:) -> UISceneConfiguration - 새 씬이나 윈도우가 필요할 때마다 호출됨 - 앱 시작시 호출되지 않고 새 씬이나 창을 가져야 하는 경우에만 호출됨 - application(_ : didDiscardSceneSessions:) - 씬을 삭제할 때(예: 멀티 태스킹 창에서 스와이프) 또는 프로그래밍 방식으로 엡 제거시 호출 - Scene Delegate - 화면에 표시될 내용(Scene/Window)을 관리 - UI Life Cycle 관리 - Entered Foreground, Became Active 상태 등은 Scene Delegate에서 관리 - UISceneSession의 Scene 생성, 파괴 및 상태 복원과 같은 Scene의 생명주기 이벤트 처리 - 하나의 앱은 여러개의 Scene과 SceneDelegate 객체를 동시에 활성화시킬 수 있음 ### 꼬리 질문: UISceneDelegate는 직접 객체를 생성하면 안되는데 왜 그럴까요? - SceneSession 및 Scene Configuration의 관리 시스템 기반으로 UIKit이 자동으로 UISceneDelegate 객체를 관리하도록 설계되었기 때문에 직접 UISceneDelegate 객체를 생성하면 이러한 시스템 관리 및 복잡성을 증가시킬 수 있으며, 예기치 않은 동작을 초래할 수 있다. #### 2. UI 객체들의 계층 구조와 각 역할에 대해 설명해주세요. |~iOS 12|iOS 13 ~| |:-:|:-:| |<img src="https://hackmd.io/_uploads/B1UVtBpWT.png" width="1000">|<img src="https://hackmd.io/_uploads/r1uEYSTWa.png" width="1000">| - `UIView` - 화면에 컨텐츠를 그리고 사용자와 직접 상호작용하여 처리하는 객체 - UI의 기본 클래스로 다른 뷰 또는 컨트롤 요소 계층 - `UIWindow` - UIView의 서브 클래스로 앱의 UI에 대한 배경과 이벤트를 뷰에 전달하는 객체 - iOS 13 이전까지는 하나의 앱에서는 하나의 Window를 가졌지만 이후부터는 아이패드 지원으로 인해 AppDelegate와 SceneDelegate의 분리로 여러 개의 Window를 가질 수 있게 되었음 - `UIWindowScene` - UIScene의 서브 클래스로 1개 또는 그 이상의 Window를 관리하는 객체 - window와 scene 두 가지의 프로퍼티를 갖음 - 해당 객체는 직접 생성을 권유하지 않음. 따라서 info.plist에서 configuration time에 UIWindowScene 객체를 사용할 클래스의 이름을 지정하여 사용하는 것을 권장 - `UIScreen` - 하드웨어 기반 디스플레이와 관련된 속성을 정의하는 객체 - 하나 이상의 연결된 디스플레이에 대한 속성과 메서드를 제공하여 화면 크기, 해상도, 화면 방향 같은 관련 정보를 설정하는 데 사용됨 ## GCD와 Operation의 차이에 대해 설명해주세요. #### DispatchQueue - Serial / Concurrent로 나뉘어 순차적, 병렬적 처리가 모두 가능하지만 늘 FIFO 방식으로 실행된다 - **꼬리질문: DispatchQueue에는 우선순위 처리방식이 없을까요?** - 동시 처리일 경우 QoS 파라미터를 사용해서 우선순위 지정 가능 - userInteractive, userInitiated, default, utility, background - 왼쪽으로 갈수록 빨리 처리되고, userInteractive는 유저와 상호작용도 가능. 기본값은 default - UI 관련일 경우 userInteractive로 사용하는 것이 좋다 - 길게 지속되는 작업은 utility, 사용자에게 직접적으로 인지되지 않아도 되는 부분은 background 권장 - 우선순위가 높은 작업은 더 많은 thread에 배치된다 - (비고: 큐 자체에도 우선순위를 줄 수 있고, 작업을 대기열에 보내는 방식에도 QoS 값을 줄 수 있다. 이때 큐와 작업의 우선순위가 각자 다르다면 해당 작업이 끝날 때까지 둘 중 더 높은 쪽으로 자동 조절된다.) - sync는 스레드를 재사용, async는 새로 생성 -> async 사용시 무한으로 늘어날 수 있음 - 기본적으로 멀티스레딩 방식이기 때문에 Thread Explosion을 야기할 수 있음 #### OperationQueue - Operation 객체들을 priority에 의해서 실행시키는 queue - 디스패치 큐의 코코아 대체제. NSOperationQueue 클래스 기반 - 오퍼레이션 큐는 언제나 동시적으로 진행되긴 하지만 순차적인 실행이 필요할 경우 디펜던시를 활용할 수 있다 -> FIFO가 아닌 우선순위 기반 처리를 진행함(우선순의 팩터를 전달받음) - 오퍼레이션 큐에 넣는 태스크는 반드시 NSOperation 클래스 인스턴스여야 함 - 오퍼레이션 객체들은 KVO 알림을 생성해준다 - 일시중지, 다시시작, 취소 가능(취소 작업시 동작은 하단 참조). 기능은 많이 제공해주지만 때문에 더 무겁기도 함 - 동시 실행 가능한 연산의 최대수 지정 가능 - **꼬리질문: DispatchQueue를 활용하여 이 부분을 비슷하게 구현할 수는 없을까요?** - DispatchSemaphore 활용할 수 있음 ### 어떤 경우에 각각의 기술을 선택할지 자신의 선택 기준에 대해 알려주세요. ### 각각의 기술을 사용할 때 작업을 취소하면 곧바로 취소가 되나요? - **GCD**: 작업을 취소하거나 중단하는 과정이 복잡하며 직접 처리해야 함. 이때 이미 시작된 작업은 취소되지 않음. - **Operation**: Operation, OperationQueue는 작업을 취소하거나 중단하는 메커니즘을 제공하기 때문에 작업취소할 때 더 용이함. 이미 시작된 작업이 취소되었을 경우 해당 작업을 중지하고 완료된 것으로 표시함. #### 작업을 취소할 때 벌어지는 일에 대해서 설명해주세요. - **DispatchQueue** - 취소 후에는 작업 항목을 실행하려는 시도가 모두 반환됨. 이미 시작된 작업 항목의 실행에는 영향을 미치지 않음. - 관련 자원의 해제는 블록 객체의 실행이 다음에 시도될 때까지(또는 이미 진행 중인 실행이 완료될 때까지) 지연됨. - **OperationQueue** - 작업 객체를 취소해도 객체는 대기열에서 사라지지 않음. 하지만 가능한 한 빨리 작업을 중지해야 한다고 객체에 알림. - 현재 실행 중인 작업의 경우, 작업 객체의 작업 코드가 취소 상태를 확인하고, 하고 있는 일을 중지하고, 완료된 것으로 표시함. - 대기열에 있지만 아직 실행되지 않은 작업의 경우, 대기열은 여전히 작업 객체의 start() 메서드를 호출하여 취소 이벤트를 처리하고 완료된 것으로 표시함. --- 📌 메리 질문 답변 --- ## 1. Singleton 디자인 패턴을 활용하는 경우를 예를 들어 설명해주세요 `Singleton` 디자인 패턴은 어떤 클래스가 단 하나의 인스턴스만을 갖도록 보장하는 패턴 `Singleton`은 전역 상태를 유지하거나, 공통된 리소스에 접근할 때 유용함 ### 1-1 **Singleton 패턴을 활용하는 경우** 유일한 인스턴스 생성을 보장하고 전역에서 액세스가 필요한 경우 사용할 수 있음 ```swift final class NumberFormatManager { // MARK: - Static Property static let shared = NumberFormatManager() // MARK: - Private Property private let formatter = NumberFormatter() // MARK: - Life Cycle private init() { } // MARK: - Function // ... } ``` - `NumberFormatter`와 같이 인스턴스를 생성하는 작업이 큰 작업에 해당하는 경우 하나의 매니저를 `Singleton` 패턴으로 만들어 전역에서 접근하도록 할 수 있음 ### 1-1-꼬리질문 **Swift에서의 Singleton 사용** ```swift UIScreen.main UserDefaults.standard UIApplication.shared FileManager.default NotificationCenter.default ``` ### 1-2 **Singleton 디자인 패턴의 장단점을 설명해주세요** **장점** - 유일한 인스턴스 - 자원 관리가 쉬움 - 전역 액세스가 가능 **단점** - 전역 액세스가 가능 - 변경점을 찾기가 어려움 - `static`하기 때문에 데이터 영역에 메모리가 잡혀있음 - `SRP`, `DIP`, `OCP` 위배 ### 1-2-꼬리질문 `SRP`, `DIP`, `OCP`를(또는 이중 1개) 어떻게 위배하는지 설명해주세요 ## 2. Core Graphics에 대해 설명해주세요 `Core Graphics`은 iOS 및 macOS 애플리케이션에서 2D 그래픽을 그리고 조작하는 데 사용되는 프레임워크 ### 2-1 **Core Graphics의 context에 대해 설명해주세요** **CGContext** > A Quartz 2D drawing environment. `context`는 그리기 작업을 수행하는 환경이며, 그래픽 스트림을 생성하고 출력하는 데 사용되고 화면에 그림을 그리거나 PDF 파일로 저장하는 등의 작업을 수행 <br> ## 3. View Contoller의 View의 상태변화에 따른 메서드의 호출순서를 이야기해보세요 **View 상태 메서드** 1. loadView(): 뷰 컨트롤러가 뷰를 로드할 때 호출 2. viewDidLoad(): 뷰가 로드된 후에 호출 3. viewWillAppear(_:): 뷰가 화면에 나타나기 직전에 호출 4. viewIsAppearing(_:): 뷰컨트롤러에게 뷰를 뷰 계층에 추가하고 있음을 알림 5. viewDidAppear(_:): 뷰가 화면에 나타난 후에 호출 6. viewWillDisappear(_:): 뷰가 화면에서 사라지기 직전에 호출 7. viewDidDisappear(_:): 뷰가 화면에서 사라진 후에 호출 **View 레이아웃 메서드** 1. viewWillLayoutSubviews(): 뷰의 하위 뷰가 레이아웃을 업데이트하기 직전에 호출 2. viewDidLayoutSubviews(): 뷰의 하위 뷰가 레이아웃을 업데이트한 후 호출 ![](https://hackmd.io/_uploads/ryULSB6ba.png) ### 3-1 **viewWillAppear와 viewDidAppear에서 무엇을 하면 좋을까요?** **viewWillAppear** 뷰 컨트롤러가 화면에 나타날 때 필요한 작업 **viewDidAppear** 뷰 컨트롤러가 화면에 나타난 직후에 실행해야 하는 작업 ### 3-2 **UIView의 layoutSubviews 메서드는 viewWillAppear보다 먼저 호출되나요? 그렇게 생각한 이유는 무엇인가요?** `viewWillAppear`가 먼저 호출됨 뷰가 로드된 후 뷰가 나타나기 직전에 레이아웃이 설정되기 때문에 `layoutSubviews`는 `viewWillAppear` 보다 늦게 그리고 `viewDidAppear` 보다 빨리 호출됨 <br> ## 4. 스위프트 언어의 String에서 subscript를 통해 문자에 접근할 수 없는 이유에 대해 설명해주세요. `Swift`에서 `Character`는 1개 이상의 `Unicode Scalar`로 이루어져 있어 크기가 가변적이기 때문에 `subscript`를 통해 문자에 접근할 수 없고 `String.index`로 접근해야함 <br> ## 5. Custom View를 구현하려면 어떻게 해야하는지 설명해주세요 1. `UIView`를 상속 받는 `Custom View` 객체 생성 2. 코드를 이용한 `UI` 구현 3. 이벤트 동작 및 핸들링 함수 추가 ### 5-1 **인터페이스빌더로 UI짜는거랑, 코드로만 UI를 짜는거랑 장단점** |장단점|스토리보드|코드베이스| |---|---|---| |장점|- 눈으로쉽게보면서레이아웃작업가능<br>- 뷰 컨트롤러에 추가적인 코드작업 필요없음<br>- 레이아웃 에러찾기 쉬움|- 어떤 일이 일어나는 지 알 수 있음<br>- 개발자 마음대로 제어가 가능<br>- 충돌 시 해결 쉬움<br>- 재사용성| |단점|- 충돌시 골치아픔 <br>- 코드로 작성한 UI에 비해 오버 헤드가 큼| - 개발기간이 XIB에 비해 큼 <br>- 에러찾기 어려움 <br>- 오래된 코드일 경우 리팩토링 어려움| 그외 장단점 1. 스토리보드 (1) 장점 - 구현하기 쉽다. - 프로토타입을 빠르게 만들 수 있다. - 화면 전환(실행흐름)을 쉽게 파악할 수 있다. - Static Cell을 이용할 수 있다. (스토리보드에서만 가능한 기능) (2) 단점 - 여러 사람이 함께 작업하는 경우, Merge 충돌이 일어날 수 있다. - 재사용 시, 뷰 컨트롤러 자체를 함께 복사해야 하기 때문에 재사용성이 낮다. - 스토리보드는 의존하는 모든 뷰 컨트롤러들과 함께 이동되어야함 - 스토리보드는 뷰 컨트롤러 사이의 실행 흐름을 다루지만, 데이터의 흐름은 관여하지 않는다. 2. Code (1) 장점 - 하나하나 코드로 구현되어 있기 때문에 기능의 정의가 직관적이다. - 읽기 쉽고, 유지보수가 간편하다. - 스토리보드와 xib로도 할 수 있는 것과 두 기능으로는 할 수 없는 것 모두 코드로는 구현할 수 있다. - UI를 코드로 작성하면 더 많은 제어와 이해를 할 수 있고, 다양하게 구현할 수 있다. - 코드만이 유일한 방법인 경우가 있다. 예를 들어 뷰가 이리저리 움직이는 다이나믹 레이아웃이나, 내용물에 기반을 두고 변화하는 레이아웃 등이 있다. - 분명한 문법적 의미를 갖고 있기 때문에 충돌을 해결하는 것이 그리 어렵지 않다. - 성능 관점에서 스토리보드와 Xib는 로드와 파싱에 대한 오버헤드를 거치고 최종에서야 간접적으로 코드로 변환되는 반면에, 코드로 만들면 이런 과정이 필요 없다. (2) 단점 - 다른 사람이 개발했던 코드를 리팩토링하기 복잡하다. - 레이아웃이 화면에 어덯게 보여지고 작동하는지 보여주기 위해 작업해야하는 시간이 xib, 스토리보드에 비해 오래 걸린다. <br>