이 문서는 2013s 01. 기준으로 작성된 글이므로, 이후에 애플 문서의 내용이 변경될 수 있습니다.
또한 전문 번역가가 아니기 때문에 의역, 오역의 소지가 다분히 많습니다.
참고하시기 바랍니다.

공개 수배 합니다!
유용한 iOS 개발문서를 함께 번역해 나갈 분들을 찾습니다.
현재도 함께 작업중이신 분들 모두 전문 번역가 아닙니다.
모두 열정과 열의로 함께 작업하고 계십니다.
자신의 재능을 자신뿐만 아니라 또 다른 누군가를 위해서 사용한다면 더더욱 빛이 날 것입니다.
함께하길 원하는 분께서는 덧글 또는 이메일 주시기 바랍니다 :)
 

오늘의 주제

1. Manage App State Changes


파헤치기 다섯 번째 시간입니다.^^

이번 파트는 Scott Lim 님께서 도와주셨습니다. 번역에 도움주셔서 진심으로 고맙습니다 :)

자, 그럼 출발해 봅시다^^~
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile2.uf@1979C54150E41B6B32FD56.png%7Cwidth=%22212%22%20height=%22619%22%20alt=%22%22%20filename=%221.png%22%20filemime=%22image/jpeg%22%7C_##]
# App States and Multitasking





iOS 어플리케이션에서는, 당신의 어플리케이션이 "현재 실행(foreground)" 상태인지 "백그라운드실행상태(background)" 인지를 아는 것이 중요하다. 시스템 리소스가 iOS 장치에 매우 한계가 정해져 있으므로, 어플리케이션은 현재 실행상태일 떄보다 백그라운드 실행상태일때 다르게 작동해야만 한다. 운영체제 또한 배터리 수명을 향상시키고, 사용자들의 현재 실행중인 어플리케이션에 대한 사용경험을 향상시키기 위해 백그라운드 실행상태인 어플리케이션이 할 수 있는 것들에 한계를 두어야만 한다. 운영체제는 당신의 어플리케이션에게 실행중상태와 백그라운드 실행상태를 이동할 때마다 알려줄 것이다. 이런 알림은 당신의 어플리케이션의 동작을 수정하는 기회가 된다.
당신의 어플리케이션이 현재 실행중인 동안, 시스템은 프로세스처리(processing)를 위해 터치 이벤트를 어플리케이션에게 보낸다. UlKit 구조는 당신의 전용(custom) 오브젝트에 이벤트를 전달하기 위한 어려운 작업의 대부분을 수행한다. 당신이 해야하는 것은 이런 이벤트들을 처리하기 위해 적당한 오브젝트에 이 메소드를 오버라이드 하는 것이 전부다. 작동을 위해, UlKit 는 텍스트 필드의 값의 변화 같은 어떤 흥비로운 일이 발생할떄만 당신의 전용(custom) 코드를 불러낸다거나, 당신을 위한 터치 이벤트를 다루는 것으로 훨씬 간단하게 작동하도록 해준다.
당신의 앱을 구현하고 싶다면, 이 가이드라인을 따라하십시오.
- (필수사항) 발생하는 상태 변화(state transition) 에 적합하게 반응하십시오. 이러한 변화들을 적절하게 다루지 못하는 것은 데이터 손실이나 사용자들에게 나쁜 인상을 가져올 수 있습니다. 상태 변이에 반응하는 방법의 요약본을 찾는다면, "Managing App State Changes" 를 보십시오.

- (필수사항) 백그라운드 실행상태로 이동할 땐, 당신의 앱이 그 동작을 적절하게 조정할 수 있는지 확실하게 해라. 당신의 앱이 백그라운드 실행상태로 이동할 때, 해야하는 것들에 대한 가이드라인을 찾는다면, "Being a Responsible Background App" 를 보십시오.

- (권장사항) 당신의 앱이 필요로 하는 시스템 변화를 알려주는 모든 알림기능을 등록하십시오. 앱이 잠자기(suspended) 상태(아무 동작도 하지 않음)일 때, 시스템은 앱이 실행을 재개하게 될 때 키 알림을 보낸다(queue). 앱은 다시 실행으로 돌아가는 부드러운 변이를 만들어내기 위해 이런 알림기능을 사용해야만 한다. 더 많은 정보를 찾는다면, "Processing Queued Notifications at Wakeup Time" 을 보십시오.

- (선택사항) 만약 당신의 앱이 백그라운드 실행상태에서 실제 작업을 수행할 필요가 있는 경우, 시스템에게 실행을 계속할 수 있는 적합한 허용을 요청해라. 당신이 할 수 있는 백그라운드 실행상태에서의 작업의 종류와 그 작업을 하기 위해 허가를 요청하는 방법에 대해 알고 싶다면, "Background Execution and Multitasking" 을 보십시오.



Managing App State Changes
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile25.uf@157A8F4150E41B7D31B6C7.png%7Cwidth=%22824%22%20height=%22295%22%20alt=%22%22%20filename=%223.png%22%20filemime=%22image/jpeg%22%7C_##]
어떤 주어진 상황에서든, 당신의 앱은 Table 3.1 에 나열된 상태 중의 한가지에 있어야 한다. 시스템은 시스템을 통해 일어나는 액션들의 반응으로 상태를 변화시킨다. 예를 들면, 사용자가 홈버튼을 눌렀을 때, 전화가 왔을 때, 또는 어떤 다른 인터럽션(interruptions)이 발생했을 때, 현재 실행중인 앱은 그에 대한 응답으로 상태를 변화시킨다. Figure 3-1 은 다른 상태로 변할 때 앱이 선택하게 되는 경로들을 보여준다.


Table 3-1    앱 상태들
실행중이 아님   :  앱이 실행되지 않았거나, 실행은 되고 있었으나 시스템에 의해 종료됨.

비활성 상태      :  앱이 실행상테에서(현재 메인 화면에서) 실행중이지만, 현재 이벤트를 받고 있지 않고 있다. (다른 코드를 수행하고 있을 수 있다.) 어플리케이션은 보통 다른 상태로의 변이가 일어날 때 일시적으로 이 상태에 머물러 있는다.

활성 상태  :  앱이 메인화면에서 실행중이고, 이벤트를 받고 있다. 이것은 실행상태의 앱의 일반적인 상태이다.
백그라운드 실행 상태 : 앱이 백그라운드 상태에 있으면서 코드를 수행하고 있다. 대부분의 앱들은 종료되어가는 과정에서 일시적으로 이 상태에 들어가게 된다. 그러나, 추가적인 실행 시간을 요청하는 앱은 일정 시간동안 이 상태에 남아있을 수 있다. 게다가, 바로 백그라운드 실행상태로 시작되는 앱은

비활성 상태(Inactive)대신 이 상태로 들어간다. 백그라운드 실행상태에 있는 동안 코드를 실행하는 방법에 대한 정보를 알고 싶다면, "Background Execution and Multitasking" 을 보십시오.

잠자기 상태  :  앱이 백그라운드 상태로 있지만, 코드를 수행하고 있지 않는다. 시스템은 그렇게 하기 전에 앱을 자동으로 이 상태로 옮기고 통지하지 않는다. 잠자기(suspended) 상태인 동안, 앱은 메모리에 남아있으나 어떤 코드도 수행하지 않는다. 메모리 부족 상태(low-memory)가 발생할 때, 시스템은 실행상태의 앱에 더 많은 공간을 만들어주기 위해 통지 없이 잠자기 상태(suspended) 앱들을 제거할 수 있다.

[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile24.uf@23307C3E50E41BA224ADE4.png%7Cwidth=%22824%22%20height=%22378%22%20alt=%22%22%20filename=%224.png%22%20filemime=%22image/jpeg%22%7C_##]Figure 3-1  





주의: iOS3.2 나 그 이전 버전에서 실행되는 앱들은 백그라운드 실행상태나 잠자기(suspended) 상태가 되지 못한다. 게다가, 어떤 장치들은 멀티태스킹이나 백그라운드 실행상태 수행을 전혀 지원하지 않는다,(심지어 iOS 4나 그 이후에서 실행되더라도). 이러한 장치들에서 실행되는 앱들은 또한 백그라운드 실행상태나 잠자기(suspended) 상태로 들어가지 못한다. 대신, 앱들은 실행상태를 떠나면서 종료된다.


[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile25.uf@24307C3E50E41BA22512F1.png%7Cwidth=%22824%22%20height=%22150%22%20alt=%22%22%20filename=%225.png%22%20filemime=%22image/jpeg%22%7C_##]
대부분의 상태 변화는 당신의 앱에 delegate object 의 메소드에 따라 상응하는 호출에 동반된다. 이러한 메소드들은 적합한 방법으로 상태 변화에 응답하는 기회(chance)가 된다. 이러한 메소드들은 아래에 당신이 사용하는 방법의 요약과 함께 나와있다.


- application:willFinishLaunchingWithOptions : 이 메소드는 당신의 앱이 실행(Launch) 시에 코드를 수행하는 첫 번째 기회가 된다.

- application:didFinishLaunchingWithOptions : 이 메소드는 당신이 당신의 앱이 사용자에게 보여지기 전에 최종적으로 어떤 초기화든지 수행하도록 해준다.

- applicationDidBecomeActive : 당신의 앱이 실행상태로 막 되려고 한다는 것을 알게 해준다. 어떠한 마지막 준비 시기(preperation)에도 이 메소드를 사용해라. 
- applicationWillResignActive : 당신에게 당신의 앱이 실행상태에서 다른 상태로 변이될 것을 알려준다. 당신의 앱을 조용한(quiescent) 상태로 놓고자 할 때, 이 메소드를 사용해라.

- applicationDidEnterBackground : 당신에게 당신의 앱이 백그라운드 실행상태로 실행되고, 어떤 때든지 잠자기(suspended) 상태로 갈 수 있음을 알려준다.

- applicationWillEnterForeground : 당신에게 당신의 앱이 백그라운드 실행상태에서 나와서 실행상태로 돌아가는 것을 알게 해준다. 그러나, 아직은 실행상태는 아니다.

- applicationWillTerminate : 당신에게 당신의 앱이 종료될 것임을 알려준다. 이 메소드는 당신의 앱이 잠자기(suspended) 상태일 때는 호출되지 않는다.


The App Launch Cycle
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile29.uf@25307C3E50E41BA226953B.png%7Cwidth=%22824%22%20height=%2283%22%20alt=%22%22%20filename=%226.png%22%20filemime=%22image/jpeg%22%7C_##]
당신의 앱이 시작되었을 때, 실행상태나 백그라운드 실행 상태로 이동하는 것이 아니라, 일시적으로 비활성상태를 통해 변이하게 된다. 실행 사이클의 부분으로서, 시스템은 프로세스를 만들고 당신의 앱을 위한 메인 쓰레드를 만들고, 당신의 앱의 메인 함수를 그 메인 쓰레드에 호출한다. 당신의 XCode 프로젝트와 함께 나오는 기본 메인 함수는 신속하게 컨트롤을 UlKit Framework 로  넘겨주는데, 이 컨트롤들은 당신의 앱을 초기화하고, 실행되는데 준비되도록 하는 작업의 대부분을 수행한다.
Figure 3-2 는 앱이 실행상태로 시작될 때, 호출된 앱 delegate 메소드를 포함해서 발생하는 이벤트들의 순서들을 보여준다.


Figure 3-2  앱을 실행상태로 시작하는 과정
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile26.uf@134E564D50E41BD3238DFF.png%7Cwidth=%22824%22%20height=%22501%22%20alt=%22%22%20filename=%227.png%22%20filemime=%22image/jpeg%22%7C_##]

만약 당신의 앱이 백그라운드 실행상태로 시작되었다면 - 보통 백그라운드 실행상태의 이벤트들을 다루기 위해 - 시작 사이클은 Figure 3-3 에 보인 것처럼 살짝 바뀐다. 중요한 차이점은 당신의 앱을 활성상태로 만드는 대신에, 이벤트를 다루기 위한 백그라운드 실행상태로 들어가서 그 후에 금방 잠자기(suspended) 상태가 된다. 백그라운드 실행상태로 시작했을때, 시스템은 여전히 앱 사용자의 인터페이스 파일을 로드하지만  앱 창에는 보여주지 않는다.



Figure 3-3 앱을 백그라운드 실행상태로 시작하는 과정
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile29.uf@154E564D50E41BD424EBF4.png%7Cwidth=%22824%22%20height=%22621%22%20alt=%22%22%20filename=%228.png%22%20filemime=%22image/jpeg%22%7C_##]
당신의 앱이 실행상태 또는 백그라운드 실행상태로 시작되는지를 결정하기 위해서는, 당신의 application:willFinishLaunchingWithOptions: 또는 application:didFinishLaunchingWithOptions 델리게이트 메소드에 있는 공유된 UIApplication object 의 applicationState 프로퍼티를 체크하여라. 앱이 실행상태로 시작되었을 때는, 이 프로퍼티는 UIApplicationStateInactive 값을 포함한다. 앱이 비실행상태로 시작된다면, 프로퍼티는 UIApplicationStateBackground 값을 대신 포함한다. 당신은 당신의 델리게이트 메소드의 시작시간 행동을 조정하기 위해 이런 차이점들을 각각 맞추어 사용할 수 있다.

주의 : 앱이 URL을 열 수 있도록 시작되었을 땐, Startup 이벤트의 과정이 Figure 3-2, 3-3 에 보여진 것들과는 조금 다르다. URL을 열 때 발생하는 Startup 과정들에 대한 정보를 알고 싶으면, "Handling URL Requests" 를 보십시오.



About the main Function
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile4.uf@174E564D50E41BD5254F0D.png%7Cwidth=%22824%22%20height=%22262%22%20alt=%22%22%20filename=%229.png%22%20filemime=%22image/jpeg%22%7C_##] C 기반의 앱과 마찬가지로, iOS 앱의 주된 시작점은 메인 함수(main function)이다. iOS 앱에서 메인 함수는 최소한으로만 사용된다. 메인 함수의 주된 역할은 UlKit fraomwork 로 컨트롤을 전달하는 것이다. 그러므로, XCode 에서 당신이 만드는 어떤 새로운 프로젝트라도 Listing 3-1 에 보이는 것 처럼 기본 메인 함수를 가지고 시작한다. 거의 예외 없이, 당신은 이 함수의 구현을 결코 바꾸어선 안된다.


Listing 3-1   iOS 앱의 메인 함수
( 코드 내용 생략 )
 
주의 : 메모리 관리에서 autorelease pool 이 사용된다. 이는 functional block of code 동안 만들어지는 object의 release 를 지연시켜주는데 사용되는 Cocoa 메커니즘이다. autorelease pools 에 대한 더 많은 정보를 원한다면, Advanced Memory Management Programming Guide 를 보십시오.







UIApplicationMain 함수는 4개의 변수를 택하고, 이를 앱을 초기화하는 데 사용한다. 당신은 이 함수로 전해지는 초기 값들을 결코 바꾸어선 안된다. 그렇지만 그 목적이나 그들이 앱을 시작하는 방법 등을 이해하는 것은 중요하다.
- argc 와 argv 변수는 시스템으로부터 앱으로 전달되는 모든 시작 시간(Launch-time) 인수 (Arguments) 들을 포함한다. 이 인수들은 UlKit infrastructure 에 의하여 분석되고, 그렇지 않다면 무시될 수 있다.

- 3번째 변수는 중요한 앱 클래스의 이름을 식별한다. 이것은 앱을 실행하는데 책임이 있는 클래스이다. 이 변수에 nil 을 사용하길 권장하는데, 이는 UIKit 이 UIApplication 클래스를 사용하도록 유도한다.

- 4번째 변수는 당신의 전용(custom) 앱 델리게이트의 클래스를 식별한다. 당신의 앱 델리게이트는 시스템과 당신의 코드 사이의 수준높은 상호작용을 다루는 데 책임이 있다. Xcode 템플릿 프로젝트는 이 변수를 자동으로 적당한 값으로 세팅한다.


UIApplicationMain 함수가 하는 또다른 일은 앱의 메인 사용자의 인터페이스 파일을 로드(Load)하는 것이다. 주요 인터페이스 파일은 당신이 당신의 앱의 사용자 인터페이스에 보여주도록 계획한 초기 view-related objects 들을 포함한다. 스토리보드를 사용하는 앱에 대해선, 이 함수는 당신의 스토리보드로 부터 초기 뷰 컨트롤러를 로드하고 당신의 앱 델리게이트에 의해 공급된 윈도우에 그것을 설치한다.  nib 파일을 사용하는 앱에선, 그 함수는 메모리로 nib 파일의 내용을 로드한다, 그러나 당신의 앱 윈도우에는 설치하진 않는다; 당신은 당신의 앱 델리게이트의 application:willFinishLaunchingWithOptions: 메소드에서 그것들을 설치해야만 한다.

앱은 메인 스토리보드 파일이나 메인 nib 파일 중 하나를 가질 수 있다, 그러나 동시에 둘다 가질 수는 없다. 스토리보드는 당신의 앱의 사용자 인터페이스를 구체화하는 방법으로 선호된다. 하지만 iOS 모든 버전에 지원되지는 않는다. 당신의 앱의 메인 스토리보드 파일의 이름은 당신의 앱의 Info.plist 파일의 UIMainStoryboardFile 키값에 저장된다. (nib 기반 앱에 대해서는, 대신에 메인 nib file 의 이름이 NSMainNibFile 키에 저장된다.) 일반적으로, Xcode 는 당신이 프로젝트를 만들 때, 적당한 키값을 정한다, 그러나 필요하다면 당신은 그 값을 바꿀 수 있다.

Info.plist 파일과 당신의 앱을 설정하기 위해 그 파일을 사용하는 방법에 대한 더 많은 정보를 원한다면, "The information Property List File" 을 보십시오.


What to Do at Launch Time
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile3.uf@135A9F3350E41C22132B4A.png%7Cwidth=%22824%22%20height=%22134%22%20alt=%22%22%20filename=%2211.png%22%20filemime=%22image/jpeg%22%7C_##]
당신의 앱이 시작되었을 때 (실행상태든 백그라운드 실행상태든) 당신의 앱 델리게이트의 application:willFinishLaunchingWithOptions:와 application:didFinishLaunchingWithOptions: 메소드를 다음 내용을 구현하도록 사용하여라.

- 앱이 실행된 이유에 대한 정보를 찾는 실행 옵션 사전 (Launch options dictionary) 의 내용들을 확인하고, 알맞게 대응해라.

- 어플리케이션의 중요 데이터 구조를 초기화하여라.

- 보여질 앱의 윈도우와 뷰를 준비하여라.

OpenGL ES 를 사용하는 앱들은 그들의 그려낸 배경등을 준비하기 위해 이 방법을 써서는 안된다. 대신, 그들은 applicationDidBecomeActive: 메소드에 전달되는 모든 OpenGL ES 호출을 지연시켜야 한다.

[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile8.uf@145A9F3350E41C22142077.png%7Cwidth=%22824%22%20height=%22130%22%20alt=%22%22%20filename=%2212.png%22%20filemime=%22image/jpeg%22%7C_##]

만약 당신의 앱이 시작 시간에 자동으로 메인 스토리보드나 nib 파일을 불러오지 않는다면, 당신은 보여주기 위한 당신 앱의 윈도우를 준비하기 위하여 application:willFinishLaunchingWithOptions: 메소드를 사용할 수 있다.
가로, 세로방향을 전부 지원하는 앱에 대해선, 항상 당신의 메인 윈도우의 root view controller 를 세로 방향으로 설정하여라. 만약 장치가 시작 시간에 다른 방향으로 놓인다면, 윈도우를 보여주기 전에 시스템이 root view controller 에게 당신의 뷰를 올바른 방향으로 회전하라고 말해줄 것이다.

당신의 application:willFinishLaunchingWithOptions: 와 application:didFinishLaunchingWithOptions: 메소드들은 항상 당신의 앱의 시작 시간을 줄이기 위해 가능한 가벼워야만 한다. 앱들은 5초 이내에 그들 자신을 초기화하고 시작하고 이벤트들을 다루도록 기대되어 진다. 만약 앱이 적절한 시간에 시작 사이클을 완료해내지 못한다면, 시스템은 무반응 상태로 놓이기 전에 그것을 죽일 것이다. 이와 같이, 당신의 시작을 늦추는 어떤 작업들도(네트워크에 접속하는 것과 같은) 동시에 발생하지 않도록 2차 쓰레드에서 실행되어야만 한다.


실행상태로 시작할 때, 시스템은 실행 상태로의 변이를 완료하기 위해 applicationDidBecomeActive: 메소드를 호출한다. 이 메소드는 시작시간에도 그리고 백그라운드 실행상태로 변이할 때에도 호출되므로, 두 변이상태에 공통인 작업들을 수행하도록 그것을 사용하여라.
백그라운드 실행상태로 시작될 때, 도착한 각종의 이벤트들을 다루기 위해 준비상태가 되는 것 말고는 당신의 앱이 해야할 것들이 많지 않아야만 한다.






Responding to Interruptions
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile2.uf@122AFF3F50E41C791137FB.png%7Cwidth=%22824%22%20height=%22383%22%20alt=%22%22%20filename=%2213.png%22%20filemime=%22image/jpeg%22%7C_##] 전화가 왔을 때 처럼, 경보(alert) 기반의 인터럽션이 발생했을 때 어플리케이션은 사용자가 진행해야할 방법으로 유도해주기 위해서 일시적으로 비활성 상태로 이동한다. 앱은 사용자가 경보를 끝낼 떄까지 이 상태에 남아있는다. 이 지점에서, 앱은 활성 상태로 돌아가거나 백그라운드 실행상태로 이동한다. Figure 3-4는 경보기반의 인터럽션이 발생했을 때 당신의 앱을 통과하는 이벤트들의 흐름을 보여준다.
Figure 3-4. 경보기반 인터럽션을 다루기
(그림 생략)

[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile29.uf@132AFF3F50E41C79128EC0.png%7Cwidth=%22824%22%20height=%2298%22%20alt=%22%22%20filename=%2214.png%22%20filemime=%22image/jpeg%22%7C_##] iOS5 에선, 배너를 보여주는 알림은 경보기반 알림이 하는 방식처럼 당신의 앱을 비활성화시키지는 않는다. 대신, 배너는 당신의 앱 윈도우의 가장 최상층에 놓이게 되고 당신의 앱은 전처럼 터치 이벤트를 계속해서 받는다. 그러나, 만약 사용자가 알림센터(notification center)를 드러내기 위해 화면을 위에서 아래로 끌어 내리면 당신의 앱은 경보기반 인터럽션이 발생했던 것처럼 비활성 상태로 이동한다. 당신의 앱은 사용자가 또다른 앱을 시작하거나, 알림 센터를 그만둘 떄까지 비활성 상태에 남아있게 된다. 이 지점에서, 당신의 앱은 알맞은 활성 상태나 백그라운드 실행 상태로 이동하게 된다. 사용자는 어떤 알림이 배너를 보여줄 것인지, 또 경보를 보여줄 것인지 설정하기 위해 앱 셋팅 (the Setting app) 을 사용할 수 있다.

Sleep/Wake 버튼을 누르는 것은 일시적으로 당신의 앱이 비활성화되도록 하는 인터럽션의 또다른 종류이다. 사용자가 이 버튼을 눌렀을 때, 시스템은 터치 이벤트를 불능 상태로 만들고 앱을 백그라운드 실행 상태로 옮긴다, 그러나 앱의 applicationState 프로퍼티 값을 UIApplicationStateInactive ( UIApplicationStateBackground 와는 반대로) 에 할당하고, 결국 화면을 잠근다(lock). 잠긴 화면은 파일을 암호화하기 위한 데이타 보호를 사용하는 앱들을 위해 부가적인 과정을 가지고 있다. 이런 과정들은 "What to Do When an Interruption Occurs" 에 설명되어 있다.



What to Do When an Interruption Occurs
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile30.uf@222AFF3F50E41C7A132410.png%7Cwidth=%22824%22%20height=%22253%22%20alt=%22%22%20filename=%2215.png%22%20filemime=%22image/jpeg%22%7C_##]
경보기반 인터럽션은 당신의 앱에 의해 일시적인 컨트롤의 손실을 낳게 된다. 당신의 앱은 실행상태로 계속 진행된다, 하지만 시스템으로부터 터치 이벤트를 받지는 않는다.(알림 및 가속센서같은 이벤트의 종류는 계속해서 받는다.) 이 변화에 대응하여, 당신의 앱은 applicationWillResignActive: 메소드에 있는 다음의 사항을 해야만 한다.

- 타이머와 다른 주기적인 작업등을 멈춘다.
- 실행중인 모든 메타데이타 쿼리를 멈춘다.
- 어떤 새로운 작업도 시작하지 않는다.
- 동영상 재생을 멈춘다 (Airplay 인 경우만 제외하고)
- 만약 앱이 게임 중이면, 멈춤 상태(Pause state) 로 들어간다.
- OpenGL ES 의 Frame rate 를 줄인다.
- 중요하지 않은 코드를 실행하는 모든 전송 혹은 작동 큐를 중단한다(suspend).


당신의 앱이 활성 상태로 돌아갔을 때, applicationDidBecomeActive: 메소드는 applicationWillResignActive: 메소드에서 행한 모든 과정을 되돌린다. 이와 같이 재활성화 때엔 당신의 앱은 타이머를 재시작해야하고, 전송 큐를 재개해야 하고, OpenGl ES 의 Frame rate 를 다시 높여야 한다. 그러나, 게임은 자동으로 재게되지는 않는다; 게임은 사용자가 재개하기를 선택할 때 까지는 멈춤 상태로 남아있는다.

사용자가 Sleep/Wake 버튼을 눌렀을 때, NSFileProtectionComplete 보호 옵션에 의해 보호된 파일을 가진 앱들은 그 파일에 관련된 모든 레퍼런스(reference)를 닫아야만 한다. 적당한 패스워드로 설정된 장치들에서는, Sleep/Wake 버튼을 누르는 것은 화면을 잠그고, 시스템은 확실한 보호가 실행된 파일에 대한 해독 키를 사라지게끔(throw away)한다. 스크린이 잠겼을 때, 파일에 상응하는 모든 접근 시도는 무시된다. 그러므로 만약 그러한 파일을 당신이 가지고 있다면, 당신은 applicationWillResignActive: 메소드에 있는 관련된 모든 레퍼런스를 닫아야 하고, applicationDidBecomeActive: 메소드에 있는 새로운 레퍼런스를 열어야 한다.


Adjusting Your User Interface During a Phone Call



사용자가 전화를 받았을 때, 그리고 전화받는 도중 당신의 앱으로 돌아왔을 때, 상태 바(status bar) 의 세로길이는 사용자가 전화하고 있다는 사실을 나타내기 위해 커지게 된다. 비슷하게, 사용자가 전화를 끝마쳤을 때, 상태 바는 보통 사이즈로 줄어든다.
상태 바의 변화를 다루는 가장 좋은 방법은 당신의 뷰를 관리하도록 뷰 컨트롤러를 사용하는 것이다. 당신의 인터페이스에 설치되었을 때, 뷰 컨트롤러는 자동으로 상태 바 프레임 사이즈가 변할 때 그 관리되는 뷰들의 세로 길이를 조절한다.
만약 당신의 앱이 어떤 이유로 뷰 컨트롤러를 사용하지 않는다면, 당신은 UIApplicationDidChangeStatusBarFrameNotification 의 알림에 수동으로 등록함으로써 상태 바 프레임의 변화에 대응해야 한다. 이 알림에 대한 처리 부분은 상태 바의 세로 길이를 받아서 당신의 앱의 뷰에 알맞게 적응되도록 이를 사용해야 한다.



Moving to Background
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile29.uf@0260433D50E41CC92ACB16.png%7Cwidth=%22824%22%20height=%22579%22%20alt=%22%22%20filename=%2217.png%22%20filemime=%22image/jpeg%22%7C_##]사용자가 홈버튼을 눌렀을 때, Sleep/Wake 버튼을 눌렀을 때, 또는 시스템이 다른 앱을 시작했을 때, 실행상태의 앱은 비활성 상태로, 그리고 백그라운드 실행 상태로 변이한다. 이런 변이는 Figure 3-5. 에 보이는 것 처럼 앱 델리게이트의 applicationWillResignActive: 와 applicationDidEnterBackground: 메소드들을 호출하는 결과를 가져온다. applicationDidEnterBackground: 메소드에서 온 다음에, 대부분의 앱들은 결국 곧 잠자기(suspended) 상태로 이동한다. 백그라운드 실행 상태의 특정 작동을 요청하거나 (음악을 재생하는 것과 같은) 시스템으로부터 짧은 추가 실행 시간을 요청하는 앱들은 조금 더 길게 실행이 이어질 수 있다.
Figure 3-5.  실행 상태에서 백그라운드 실행 상태로의 이동 (Moving from the foreground to the background)
( 그림 생략 )

주의 : 앱들은 멀티태스킹을 지원하는 장치에서만 그리고 iOS4.0 이나 이후 버전을 실행하는 장치에서만 백그라운드 실행상태로 이동한다. 다른 모든 경우에선, 앱은 백그라운드 실행상태로 이동되는 대신 종료된다(메모리에서 부터 제거된다).


What to Do When Moving to Background




앱들은 백그라운드 실행상태로 움직이는 것에 대비해서 applicationDidEnterBackground: 메소드를 사용할 수 있다. 백그라운드 실행상태로 이동할 때, 모든 앱들은 다음의 내용을 해야만 한다.
- 현재 상태 이미지가 찍히는 것에 대한 준비를 해라. 
applicationDidEnterBackground: 메소드가 돌아왔을 때, 시스템은 당신의 앱의 사용자 인터페이스의 상태를 찍는다(picture). 그리고 변이될 에니메이션을 위한 결과 이미지를 사용한다. 만약 당신의 인터페이스의 어떤 뷰라도 민감한 정보를 포함하고 있다면, applicationDidEnterBackground: 메소드가 돌아오기 전에 그런 뷰들을 숨기거나 수정해야만 한다.

- 사용자 데이터와 앱 상태 정보를 저장해라.
모든 저장되지않은 변화들은 백그라운드 실행상태로 들어갈 때 디스크에 기록되어야만 한다. 이 단계는 당신의 앱이 백그라운드 실행 상태에 있는 동안 수많은 사유로 인해 조용히 종료될 수 있으므로 매우 필요하다. 당신은 필요에 따라 이 작업을 백그라운드 실행상태 스레드에서 수행할 수 있다.

- 가능한한 많은 메모리를 비워놓아라(Free up).
무엇을 해야하고, 왜 이것이 중요한지에 대한 더 많은 정보를 원한다면, "Memory Usage for Background Apps" 를 보십시오.

당신의 앱 델리게이트의 applicationDidEnterBackground: 메소드는 대략 모든 업무를 종료하고 돌아오는 데 5초를 가진다. 실제로, 이 메소드는 가능한 빠르게 돌아와야만 한다. 만약 메소드가 시간이 끝나기 전에 돌아오지 못한다면, 당신의 앱은 메로리로부터 종료될 것이다. 만약 당신이 여전히 작업들을 수행하는 데 더 많은 시간을 필요로 한다면, 백그라운드 실행상태의 실행 시간을 요청하기 위한 beginBackgroundTaskWithExpirationHander: 메소드를 호출하여라 그리고 2차 스레드에서 오래 걸리는 작업들을 시작해라. 당신이 어떤 백그라운드 실행상태 작업들을 실행했더라도, applicationDidEnterBackground: 메소드는 여전히 5초 내에 종료해야만 한다.


주의 : UIApplicationDidEnterBackgroundNotification 알림은 또한 당신의 앱의 특정한 부분들에게 백그라운드 실행상태로 들어간다는 것을 알리기 위해 전송된다. 당신의 앱의 오브젝트들은 이 알림에 대한 등록을 위해 이 기본 알림 센터를 사용할 수 있다.

당신의 앱의 특징들에 따라, 백그라운드 실행상태로 들어갈 때, 당신의 앱이 해야만 하는 다른 것들이 있다. 예를 들면, 모든 활성상태의 Bonjour 서비스들은 잠자기(suspended) 상태로 가야만 한다. 그리고 앱은 OpenGl ES 함수들을 호출하는 것을 멈춰야만 한다. 백그라운드 실행상태로 들어갈 때 당신의 앱이 해야만 하는 것들의 목록을 보려면, "Being a Responsible Background App" 를 보십시오.


Memory Usage for Background Apps
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile24.uf@14349C4450E41CE11F0AB6.png%7Cwidth=%22824%22%20height=%22238%22%20alt=%22%22%20filename=%2219.png%22%20filemime=%22image/jpeg%22%7C_##]
모든 앱들은 백그라운드 실행상태로 들어갈 때 실용적일 수 있을 만큼 많은 메모리를 비워놓아야만 한다. 시스템은 할 수 있는 한 동시에 메모리에 많은 앱들을 유지하려고 한다. 그러나 메모리가 부족할 때, 시스템은 메모리를 회복하기 위해 잠자기(suspended) 상태의 앱들을 종료한다. 백그라운드 실행상태에 있을 때 많은 양의 메모리를 소비하는 앱들은 종료되어야 할 첫번째 앱이 될 것이다.
실용적으로 말해서, 당신의 앱은 strong 레퍼런스가 더이상 필요하지 않게 되는 즉시 제거해야만 한다. strong 레퍼런스들을 제거하는 것은 컴파일러가 상응하는 메모리가 회복될 수 있도록 바로 오브젝트들을 release하게 해준다. 그러나 만약 당신이 퍼포먼스를 향상시키기 위해 일부 오브젝트들을 캐시(cache)에 저장하길 원한다면, 당신은 그 레퍼런스들을 제거하기 전에 앱이 백그라운드 실행상태로 변이될 떄까지 기다려야만 한다.

당신이 가능한 빠르게 strong 레퍼런스들을 제거해야만 하는 오브젝트들의 예들은 다음을 포함한다 :

- 이미지 오브젝트
- 당신이 디스크로부터 다시 불러올 수 있는 큰 미디어 혹은 데이타 파일들
- 당신의 앱이 필요로 하지 않고, 나중에 쉽게 다시 만들 수 있는 다른 모든 오브젝트들

당신의 앱의 메모리 흔적들을 줄이기 위해, 시스템은 당신의 앱이 백그라운드 실행상태로 이동할 때 당신의 앱을 대신해서 할당된 일부 데이터들을 자동으로 삭제한다.

- 시스템은 모든 Core Animation Layers 에 쓰이는 backing store 를 삭제한다.(?) 이런 수행은 메모리로부터 당신의 앱의 layer 오브젝트들을 삭제하지 않고, 현재의 layer 프로퍼티들을 바꾸지도 않는다. 그것은 단순히 그런 레이어의 컨텐츠들이 스크린에 등장하는 것을 막는데, 이는 백그라운드 실행상태의 앱이 어떻게든 실행되지 않도록 주어진다.

- 캐쉬에 저장된 이미지들의 시스템 레퍼런스들을 삭제한다. (만약 당신의 앱이 이미지들에 strong 레퍼런스를 가지고 있지 않다면, 그들은 메모리로부터 차후에 삭제될 것이다).

- 다른 시스템에 의해 관리된 캐쉬 데이터들의 strong 레퍼런스 들을 삭제한다.


Returning to the Foreground



실행상태로 돌아오는 것은 앱이 백그라운드 실행상태로 갔을 때 멈췄던 작업들을 다시 시작할 기회이다. 실행상태로 이동할 때 발생하는 단계들은 Figure 3-6. 에 나와있다. applicationWillEnterForeground: 메소드는 당신의 applicationDidEnterBackground: 메소드에서 행해진 모든 것들을 되돌려야(undo) 한다. 그리고 applicationDidBecomeActive: 메소드는 시작시간에 있었던 동일한 활성화 작업들을 계속해서 수행해야 한다.

Figure 3-6. 백그라운드 실행상태에서 실행상태로의 변이 (Transitioning from the background to foreground)

(그림 생략)


주의 : UIApplicationWillEnterForegroundNotification 알림 또한 당신의 앱이 실행상태로 다시 들어갈 때 트랙킹하는 데 사용될 수 있다. 당신이 앱의 오브젝트들은 이 알림에 등록을 위한 기본 알림 센터를 사용할 수 있다.



Processing Queued Notifications at Wakeup Time
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile27.uf@2136443F50E41D0804B24A.png%7Cwidth=%22824%22%20height=%22109%22%20alt=%22%22%20filename=%2221.png%22%20filemime=%22image/jpeg%22%7C_##]
잠자기(suspended) 상태에 있던 어플은 실행상태나 백그라운드 실행상태로 돌아올 때 모든 대기중인 알림을 다룰 준비가 되어있어야 한다. 잠자기(Suspended) 상태 앱은 어떤 코드도 실행하지 못하므로 가로,세로의 방향 변화, 시간 변화, 설정(preference) 변화 및 앱의 보이는 모습이나 상태에 영향을 줄 수 있는 다른 많은 것들에 관련된 알림을 처리할 수 없다. 이런 변화들이 손실되지 않게끔 확신하기 위해서, 시스템은 많은 관련 알림들을 큐로 내보내고 다시 코드를 시작하는 순간 (실행상태이든 백그라운드 실행상태이든) 앱에게 그 내용들을 전달한다. 재개했을 때, 알림이 오버로딩되는 걸 막기 위해서, 시스템은 이벤트들을 합치고 앱이 잠자기(suspended) 된 이후의 순수 변화만을 반영하는 하나의 알림 (또는 각각 관련된 타입들)을 전달한다.
Table 3-2. 는 합쳐져서 당신의 앱으로 전달될 수 있는 알림들을 나열했다. 이 알림들의 대부분은 등록된 옵저버들에게 직접적으로 전달된다. 장치의 화면 출력방향 (가로, 세로) 변화에 관련된 것들은 일반적으로 시스템 framework 에 의해 인터셉트되어 다른 방식으로 당신의 앱에게 전달된다.
Table 3-2.  깨어있는 앱들에 전달되는 알림들 (Notifications delivered to waking apps)



- 악세사리가 탈착 또는 부착될 때
- 기기의 가로 또는 세로로 방향 전환을 할 때
- 시간대가 변경될 때
- 배터리가 저전력 상태로 변경될 때
- 근접 센서가 작동할 때
- 보호된 파일이 변경되었을 때
- 외부 디스플레이에 연결되거나 해제되었을 때
- 디스플레이 모드가 변경되었을 때
- 설정 앱에서 내 어플의 설정이 변경되었을 때
- 언어 또는 지역이 변경되었을 때
- 사용자의 iCloud 계정이 변경되었을 때

[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile1.uf@14343D4050E41D290FFDD1.png%7Cwidth=%22824%22%20height=%2293%22%20alt=%22%22%20filename=%2223.png%22%20filemime=%22image/jpeg%22%7C_##]대기된 알림들은 당신의 앱의 메인 run loop 에 전달되고 일반적으로 다른 터치 이벤트나 다른 사용자 입력 이전에 전달된다. 대부분의 앱들은 재개되었을 때 사용자가 알아차릴 수 있는 정도의 지연이 일어나지 않을 정도로 충분히 신속하게 이런 이벤트들을 전달할 수 있어야만 한다. 그러나, 만약 당신의 앱이 백그라운드 실행상태에서 돌아왔을 때 느리게 움직이는 모습을 보인다면 당신의 알림 전달 코드가 그 지연을 일으키고 있는지 결정할 Instruments 를 사용해라.

실행상태로 돌아온 앱은 또한 마지막 업데이트 이후로 어지러워진(marked dirty) 어떤 뷰에 대해서도 뷰-업데이트 알림을 받는다. 백그라운드 실행상태에서 돌아가고 있는 앱은 여전시 setNeedDisplay 나 setNeedsDisplayInRect: 메소드들을 그 뷰의 업데이트를 요청하기 위해 호출할 수 있다. 그러나, 뷰들은 보이지 않기 때문에, 시스템은 요청들을 합치고, 앱이 실행상태로 돌아오고 난 뒤에 뷰들을 업데이트한다.


Handling iCloud Changes



만약 iCloud 의 상태가 어떤 이유든지 변하게 되면, 시스템은 당신의 앱에 NSUbiquityIdentityDidChangeNotification 알림을 전송한다. iCloud 상태는 사용자가 iCloud 계정에 로그인 혹은 아웃을 하거나 문서와 데이터의 싱크(syncing)가 가능해지거나 불가능해지는 상태로 변하게 된다. 이 알림은 변화를 수용하기 위한 캐시메모리나 모든 iCloud 관련 사용자 인터페이스 요소들을 업데이트하라는 신호이다. 예를 들면, 사용자가 iCloud 로그아웃을 했을 경우, 당신은 iCloud 기반의 모든 파일과 데이터들의 reference 를 삭제해야만 한다.

만약 당신의 앱이 이미 iCloud 에 파일을 저장할 것인지에 대해 사용자에게 전달하였다면, iCloud 상태가 변했을 때 다시 전달할 필요는 없다. 사용자에게 처음으로 전달한 후에, 당신의 앱의 위치 설정들에서 사용자의 선택을 저장해라. 당신은 그러고 나면 그 설정을 Setting 번들을 사용하거나 당신의 앱의 옵션으로서 드러내길 원할수도 있다(?). 그러나 설정이 현재 사용자 기본 데이터베이스에 있지 않다면, 그 프롬프트를 반복할 필요는 없다.


Handling Locale Changes Gracefully
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile25.uf@16316C4650E41D4D06368A.png%7Cwidth=%22824%22%20height=%22138%22%20alt=%22%22%20filename=%2225.png%22%20filemime=%22image/jpeg%22%7C_##]만약 사용자가 당신의 앱이 잠자기(suspended) 되어있는 동안 현재 언어를 변경한다면, 당신은 당신의 앱이 실행상태로 돌아왔을 때, 날짜, 시간, 숫자같은 지역(Locale)에 민감하게 관련된 정보들을 담고 있는 모든 뷰를 업데이트하도록 NSCurrentLocaleDidChangeNotification 알림을 사용할 수 있다. 물론, 언어관련된 문제점들을 피하는 가장 좋은 방법은 당신의 코드를 업데이트 뷰를 쉽게 만들 수 있는 방법으로 작성하는 것이다. 예를 들면:

- NSLocale 오브젝트들을 다시 받았을 때, autoupdatingCurrentLocale 클래스 메소드를 사용하여라. 이 메소드는 변화에 대응해서 자동으로 스스로를 업데이트 해주는 지역기반 오브젝트를 반환한다. 그래서 당신은 그것을 다시만들 필요가 없다. 그러나, 지역 변화가 일어났을 때, 당신은 여전히 현재 지역에서 전달된 내용을 포함하고 있는 뷰들을 리프레쉬 해줄 필요가 있다.

- 현재 지역 정보가 변할 때마다 캐쉬에 저장된 날짜나 숫자 formatter 오브젝트들을 다시 만들어라.
지역 변화를 다루도록 당신의 코드를 세계화하는 데 더 많은 정보를 찾는다면, Internationalization Programming Topics 를 보십시오.


Responding to Changes in Your App's Settings



만약, 당신의 앱이 셋팅 앱(Setting app)에 의해 관리되는 셋팅을 가졌다면, 당신의 앱은 NSUserDefaultsDidChangeNotification 알림을 관찰해야만 한다. 사용자는 당신의 앱이 잠자기(suspended) 상태이거나 백그라운드 실행상태인 동안 셋팅을 수정할 수 있으므로, 그러한 셋팅에서 중요한 모든 변화에 대해 응답하기 위한 이런 알림을 사용할 수 있다. 어떤 경우에서는, 이 알림에 대해 응답하는 것이 잠재적인 보안 구멍을 없애는 데 도움을 줄 수 있다. 예를 들면, 이메일 프로그램은 사용자의 계정 정보의 변화에 반응해야만 한다. 이런 변화들의 감지 실패는 프라이버시, 보안 문제점들을 야기시킬 수 있다. 구체적으로, 현재 사용자들은 계정이 더이상 그 사람에게 속해있지 않은 경우에도 예전의 계정 정보를 사용하여 이메일을 보낼 수도 있다.


NSUserDefaultsDidChangeNotification 알림을 받을 때, 당신의 앱은 모든 관련 셋팅들을 다시 로딩해야만 하고, 필요하다면 그 사용자 인터페이스를 적절하게 리셋해야 한다. 비밀번호나 다른 보안관련 정보가 변경된 경우에는, 당신은 또한 이전에 표시된 정보들을 가려야만 하고, 사용자들에게 새로운 비밀번호를 입력하도록 만들어야 한다.


App Termination
[##_http://yagom.tistory.com/script/powerEditor/pages/1C%7Ccfile4.uf@203FD84550E41D6E22F083.png%7Cwidth=%22824%22%20height=%22233%22%20alt=%22%22%20filename=%2227.png%22%20filemime=%22image/jpeg%22%7C_##]비록 일반적으로 앱들이 백그라운드 실행상태나 잠자기(suspended) 상태로 이동하였더라도, 다음에 나오는 조건들이 참값이라면, 당신의 앱은 종료되고, 메모리로부터 삭제된다.
- 앱이 iOS 4.0 이전의 버전에 반하는 연결이 되었다.
- 앱이 iOS 4.0 이전의 버전을 실행하는 장치에 배치되었다.
- 현재 장치가 멀티테스킹을 지원하지 않는다; "Determining Whether Multitasking Is Available)"을 보십시오.
- 앱이 Info.plist 파일에 UIApplicationExitsOnSuspended 키를 포함한다.; "Opting out of Background Execution" 을 보십시오.


만약 당신의 앱이 (실행상태든 백그라운드 실행상태든) 종료 시기에 실행되고 있다면, 시스템은 당신의 앱 엘리게이트의 applicationWillTerminate: 메소드를 호출하여 당신이 필요한 모든 정리(Cleanup) 을 수행할 수 있게 해준다. 당신은 현재 상태를 다음 실행 때 복원하기 위해 사용하게 되는 앱 상태 정보나 사용자 데이터 등을 저장하기 위해 이 메소드를 사용할 수 있다. 당신의 메소드는 모든 작업을 수행하고 반환하는 데 약 5초의 시간을 가질 수 있다. 만약 시간 내에 반환하지 못한다면, 앱은 메모리로부터 삭제되고 종료될 것이다.

중요: TheapplicationWillTerminate: 메소드는 만약 당신의 앱이 현재 잠자기(suspended) 상태라면 호출되지 않는다.


당신이 당신의 앱을 iOS SDK4 나 이후 버전을 사용해서 개발하는 경우, 당신은 아무 통지없이 당신의 앱이 종료되는 것에 대해 준비되어야만 한다. 사용자는 멀티태스킹 UI 를 사용하여 분명하게 앱을 종료시킬 수 있다. 게다가, 만약 메모리가 제한되었다면, 시스템은 더 많은 공간을 만들어내기 위해 앱을 메모리로부터 제거할 수도 있다. 잠자기(suspended) 상태의 앱들은 종료의 통지를 받지 않는다, 그러나 만약 당신의 앱이 백그라운드 실행 상태(잠자기(suspended) 상태가 아니라)에서 현재 돌아가고 있다면, 시스템은 당신의 앱 델리게이트의 applicationWillTerminate: 메소드를 호출한다. 당신의 앱은 이 메소드로부터 추가적인 백그라운드 실행상태 수행 시간을 요청할 수 없다.




by yagom

facebook : http://fb.yagom.net

twitter : http://twitter.yagom.net ( @yagomsoft )

p.s 제 포스팅을 RSS 피드로 받아보실 수 있습니다.

RSS Feed 받기   


↓↓↓저 열심히 썼는데 손가락 한방 꾹 눌러주고 가시는 건 어떨까요? 로그인이 필요 없습니다. ^~^ 고맙습니다~ ↓↓↓ 





저작자 표시 비영리 변경 금지
신고
Posted by yagom


티스토리 툴바