![](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() 메서드를 호출하여 취소 이벤트를 처리하고 완료된 것으로 표시함. ###