├── .gitignore ├── 13 Free Tools for API Development and Testing(Korean).md ├── App Extension Programming Guide_Today(Korean).md ├── App Programing Guide for iOS(Korean).md ├── Creating Independent watchOS Apps(Korean).md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /13 Free Tools for API Development and Testing(Korean).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # API 디자인, 개발 그리고 테스트를 위한 13가지 무료 툴 📡 4 | #### 작성자 : 전미정 5 | 6 | > 본 문서에서는 API의 다양한 기능(개발, 테스트, 디자인, 관리 등)을 무료로, 손쉽게 다룰 수있는 여러가지 서비스를 안내합니다. **목적에 부합하는 툴을 이용해 API 개발 및 관리에 익숙해지고, 실제 개발에 적용해 봅시다 :)** 7 | 8 | ### 목차 9 | [1. Amazon AWS Free Tier](#1) 10 | [2. IBM Bluemix API Management](#2) 11 | [3. Runscope](#3) 12 | [4. Restlet Studio](#4) 13 | [5. APImetrics](#5) 14 | [6. JsonStub](#6) 15 | [7. Mockable.io](#7) 16 | [8. Httpbin.org](#8) 17 | [9. Loader.io](#9) 18 | [10. BlazeMeter](#10) 19 | [11. Sandbox](#11) 20 | [12. Mocky.io](#12) 21 | [13. JOSN Server](#13) 22 | 23 | 24 | ## 1. Amazon AWS Free Tier and Amazon API Gateway 25 | 26 | ### [Free Tier for AWS](http://www.infoworld.com/article/3046613/cloud-computing/make-the-most-of-free-amazon-web-services.html) 27 | * 무료 요금제로 AWS에서 제공하는 거의 모든 기능들을 사용해 볼 수 있습니다. 28 | * 물론, 사용량에 제한이 있으므로 단순히 작업이 어떻게 이뤄지는지 파악하는 용도로 사용하는 것이 좋습니다. 29 | 30 | ### [Amazon API Gateway](http://aws.amazon.com/api-gateway/) 31 | * Amazon API Gateway는 무료 요금제(free tier)와 함께 제공되는 API 관리 서비스입니다. 32 | 33 | * 매달 1백만 건의 API 호출을 제공하므로, Amazon에서 제공하는 API 관련 기능 및 방식이 구현하려는 목적에 부합하는지 확인하는 용도로 사용하면 좋습니다. 34 | 35 | 36 | 37 | ## 2. IBM Bluemix API Management 38 | 39 | * AWS와 마찬가지로, [IBM Bluemix](https://console.ng.bluemix.net/catalog/services/api-connect/) 또한 무료 요금제를 제공하고 있습니다. 40 | * Bluemix는 개발자들이 원하는 다양한 기능을 제공하고 있지만, 무료 요금제로 실제 제품을 구축 하기는 힘듭니다. 41 | * AWS와 마찬가지로, IBM은 API 관리 도구를 제공합니다.(API Connect, API Management, Conncect & Compose) 42 | * 한달에 수만건의 API 호출이 가능하기 때문에 기능을 테스트해보는데 부족함이 없습니다. 43 | 44 | 45 | ## 3. Runscope 46 | * [Runscope](https://www.runscope.com/pricing-and-plans)는 웹 기반의 API 테스트 툴을 제공합니다. 47 | * 작성된 API가 제대로 작동하는지, 유효한 값을 반환하는지 등을 디버깅 할 수 있습니다. 48 | * 무료 요금제로 API 테스트, 가동시간 모니터링, 그리고 트래픽 디버깅 기능을 사용할 수 있으며, 한달에 최대 2.5만건 호출이 가능합니다. 49 | 50 | 51 | ## 4. Restlet Studio 52 | * [Restlet Studio](https://restlet.com/)는 "API 디자인을 위한 웹 IDE"로 불리며, 시각적 도구를 이용하고있습니다. 53 | * 메서드와 쿼리 파라미터 등의 설정 뿐만 아니라, API를 위한 Jave / Node.js 코드를 자동 생성해줍니다. 54 | * Swagger와 RAML을 모두 지원합니다. 55 | * 무료 요금제로는 단 하나의 API를 구출 할 수 있지만, API 테스트시 호출 횟수에 제한이 없습니다. (만약 제품에 사용된다면 1,000건으로 제한) 56 | 57 | 58 | ## 5. APImetrics 59 | * [APImetrics](http://apimetrics.io/)는 API를 모니터링하고 변경하는 서비스를 제공합니다. 60 | * APImetrics는 시각적인 API 디자인, 대시보드를 제공하며 REST, SOAP API를 모두 지원합니다. 61 | * 무료 요금제로는 수동 호출만 할 수 있으며, 회사의 West Coast에 위치한 서버에서만 실행 가능합니다. 62 | 63 | 64 | ## 6. JsonStub 65 | * [JsonStub](http://jsonstub.com/)의 웹 인터페이스를 통해 고정적인 텍스트(JSON)를 반환하는 API를 손쉽게 만들 수 있습니다.(mockup) 66 | * JsonStub 홈페이지에 "당신이 프론트 엔드를 개발하는 동안 백엔드를 조작하라. (Fake the back end while you develop the front end.)" 라고 나와있듯 프론트 엔드를 개발하는 동안 테스트용으로 사용하기에 유용합니다. 67 | 68 | 69 | ## 7. Mockable.io 70 | * [Mockable](https://www.mockable.io/) 역시 빠르고 간단하게 REST와 SOAP API를 제작할 수 있는 웹 사이트입니다. 71 | * 3개월 이내에 사용되지 않는 경로는 삭제되지만, Mockable의 기본 계정(base tier)는 영원히 무료입니다. 72 | * 로그는 24시간 동안만 유지되거나, 5MB를 초과하지 않는 한 영구 보존됩니다. 73 | * 가장 좋은 점은 API 제작을 위해 사이트에 계정을 등록하지 않고, 임시계정을 이용 해도 된다는 점입니다. 74 | 75 | 76 | ## 8. Httpbin.org 77 | * [Httpbin](http://httpbin.org/)은 Runscope와 유사한 기능을 제공하는데, 요청을 보내는 프론트 엔드를 테스트하거나 디버깅하는데 유용한 HTTP API endpoint response를 제공합니다. 78 | * 웹 인터페스를 통해 구성하는게 아니라, URL 파라미터를 이용해 구성할 수 있습니다. 79 | 80 | 81 | ## 9. Loader.io 82 | * 얼마나 많은 로드에 견딜 수 있는지 테스트하는 것은 public-facing API에 매우 중요한 일입니다. 83 | * [Loader.io](https://loader.io/)의 웹 인터페이스나 API를 이용해 실시간으로 API 테스트 결과를 관찰 할 수있습니다. 84 | * 무료 버전에서는 최대 10,000명의 클라이언트가 동시에 싱글 타겟을 테스트할 수 있습니다. 85 | 86 | 87 | ## 10. BlazeMeter 88 | * [BlaserMeter](https://www.blazemeter.com/)는 Loader.io와 유사한 API 로드 테스트 서비스 입니다. 89 | * 특징적인 기능은 지역기반의 로드 테스팅이 가능하다는 것입니다. (여러 대륙의 서버에서 생성된 트래픽 활용 가능) 90 | * Apache JMeter로 생성된 테스트 또한 가능합니다. 91 | * 계정에 가입하면 처음 14일 동안 Pro 버전과 동일한 기능을 사용할 수 있으며, 이후 무료 요금제에서는 각종 기능이 제한됩니다. 92 | 93 | 94 | ## 11. Sandbox 95 | * [Sandbox]{https://getsandbox.com/features}는 가볍고, 독립적인 방식으로 API를 실행 할 수 있는 시스템입니다. 96 | * REST와 SOAP 모두 지원합니다. 97 | * Apiary, Swagger, RAML, WSDL 그리고 Blank를 지원합니다. 98 | * Snadbox 회사에서 제공하는 클라우드의 무료 요금제를 이용하면 5,000건 까지 호출 할 수 있으며, Sandbox의 수는 무제한입니다. 99 | 100 | 101 | ## 12. Mocky.io 102 | * [Mocky.io](http://www.mocky.io)는 Runscope에서 제공하는 웹 기반 REST API 테스트 사이트입니다. 103 | * 로그인이나 계정 생성없이 빠르고 간단하게 HTTP response를 확인 할 수 있습니다. 104 | 105 | 106 | ## 13. JSON Server 107 | * 작성한 프론트 엔드 코드가 정상적으로 작동하는지 테스트하기 위해 서버가 준비되길 무작정 기다릴 수만은 없습니다. `npm module`의 [JSON Server](https://github.com/typicode/json-server)를 이용하면 백엔드 프로토 타입을 생성해 REST API를 테스트 해 볼 수 있습니다. 108 | * 자세한 방법 및 설명은 아래 링크를 참고하세요. 109 | * [JSON-Server as a Fave REST API in Fronted Devlopment](https://scotch.io/tutorials/json-server-as-a-fake-rest-api-in-frontend-development) 110 | * [Mock up your REST API with JSON Server](http://www.betterpixels.co.uk/projects/2015/05/09/mock-up-your-rest-api-with-json-server/) 111 | * [Create a Mock REST API in Seconds for Prototyping your Frontend](https://coligo.io/create-mock-rest-api-with-json-server/) 112 | 113 | 114 | > 본 문서는 [[원문] 10 Free Tools for API Design, Development and Testing](http://www.infoworld.com/article/3060731/apis/10-free-tools-for-api-design-development-and-testing.html#slide1)을 바탕으로, 관련된 내용을 추가 조사하여 구성하였습니다. 115 | 116 | [위로가기](#위) -------------------------------------------------------------------------------- /App Extension Programming Guide_Today(Korean).md: -------------------------------------------------------------------------------- 1 | # App Extension Programming Guide_Today(위젯) 2 | == 3 | ## 소개 4 | 애플에서 지원하는 다양한 extension 중 하나인 Today Extenstion에 관한 번역 문서입니다. 실제 애플리케이션에 위젯을 적용하기위해 공부하다 번역하게 되었습니다. 중간중간 실제 개발 스토리가 들어가있으니 함께 참고해주세요 :) 5 | 6 | ### App Extension Types 7 | 8 | * Action 9 | * Audio Unit 10 | * Conent Blocker 11 | * Custom Keyboard 12 | * Documnet Provider 13 | * Finder Sync 14 | * Photo Editing 15 | * Share 16 | * **Today** 17 | 18 | **App Extension 중 하나인 Today는 Today Extenstion/Today Widget이라 쓰이고, 흔히 Widgets(위젯)으로 불립니다.** 위젯은 사용자들이 중요한 정보에 빠르게 접근 할 수있도록 도와줍니다. 예를 들어 사용자는 위젯을 통해 현재 주가, 날씨 정보, 오늘의 일정을 확인하거나 해야 할 일을 완료했음을 체크할 수 있습니다. 사용자들은 위젯을 통해 관심있는 정보를 즉각 활용 할 수 있기 원합니다. 19 | 20 | 위젯을 잠금 화면에서도 보여지게 할 수 있는데, Setting > Touch ID & Passcode > Notifications View에서 "Allow Access When Locked"를 체크하면 됩니다. 21 | 22 | > **시작하기 전에** 23 | > Today extension의 핵심은 빠르게 정보를 업데이트하고, 간단한 작업을 수행할 수 있게 하는 것입니다. 만약 사용자에게 멀티 테스크나 시간이 오래 걸리는 작업(업로딩, 다운로딩)을 제공하려고 한다면 Today extension은 적절한 선택이 아닐 수 있습니다. 24 | 25 | 26 | ## 위젯 이해하기(Understand Today Widgets) 27 | * iOS와 macOS 플랫폼의 Today Widget은 아래 사항을 준수해야 합니다. 28 | * 위젯의 내용은 항상 최신 상태를 유지해야 합니다. 29 | * 사용자 액션에 적절하게 반응해야합니다. 30 | * 작동 성능이 좋아야합니다. (특히, iOS 위젯은 메모리를 효율적으로 사용해야합니다. 그렇지 않으면 시스템에 의해 종료될 수 있습니다.) 31 | 32 | 위젯과 사용자간의 상호작용은 제한되어있기 때문에 단순하고 유연한 UI로 디자인하여 사용자가 관심있어 하는 정보를 부각 시킬 수 있도록 해야힙니다. 이를 위해 액션 가능한 항목 수를 제한하는 것이 좋습니다. 그리고 iOS 위젯은 키보드 입력을 지원하지 않습니다. 33 | 34 | > **NOTE** 35 | > 위젯 뷰 내부에 스크롤 뷰(scroll view)를 두지 않도록 하십시오. 사용자가 위젯 화면 전체를 스크롤 하지 않고, 개별 위젯 뷰 내부를 스크롤하는 것은 어려운 일입니다. 36 | 37 | 사용자는 그들이 사용하는 플랫폼에 따라 그들이 사용하는 위젯을 각기 다르게 인식합니다. 38 | 39 | **iOS** iOS 위젯에서는 키보드 입력이 지원되지 않기 때문에, 사용자는 위젯을 포함하는 애플리케이션을 통해 위젯에 보여질 내용을 구성 할 수 있어야 합니다. 예를 들어, Stocks 위젯에서 사용자는 값을 어떤 방식으로 볼지를 변경 할 수 있지만 위젯에서 보여질 목록을 관리하기 위해서는 Stocks 애플리케이션을 실행해야합니다. 40 | 41 | **macOS** 위젯이 포함된 애플리케이션에서 어떤 기능을 제공하지 않을 수도 있기 때문에 위젯이 실행 중일때 사용자가 조절 할 수 있는 방법을 제공해야 합니다. 예를 들어 macOS의 Stocks 위젯에서 사용자는 원하는 항목을 추가할 수 있습니다. macOS의 Notification Center API는 사용자들이 위젯을 구성할 수 있는 method를 포함하고 있습니다. 42 | 43 | Today Extension을 포함하는 애플리케이션을 설치하면 사용자가 Today View에 위젯을 추가 할 수 있습니다. Today View에서 'Edit' 버튼을 누르면 Notification Center가 위젯을 추가, 삭제 그리고 재정렬하는 기능을 제공합니다. 44 | 45 | ## Xcode Today 템플릿 46 | Xcode Today 템플릿은 핵심 class`TodayViewController`를 위한 기본 헤더 파일과 구현 파일 그리고 Info.plist, 인터페이스 파일`storyboard/xib`을 제공합니다. 47 | 48 | 기본 Today 템플릿의 Info.plist은 아래와 같은 key-value을 제공합니다.(macOS) 49 | 50 | ``` 51 | NSExtension 52 | 53 | NSExtensionPointIdentifier 54 | com.apple.widget-extension 55 | NSExtensionPrincipalClass 56 | TodayViewController 57 | 58 | ``` 59 | 60 | 만일 custom view controller subclass를 사용하려면`NSExtensionPrincipalClass` key의 값인 `TodayViewController`를 custom class의 이름으로 교체하면 됩니다. 61 | 62 | **iOS** 기본으로 제공되는 storyboard를 사용하지 않으려면 `NSExtentionMainStoryboard` key를 제거하고 `NSExtensionPrincipalClass` key를 추가하고 사용하려는 `view controller`(ex. TodayViewController)의 이름을 value에 입력하십시오. 63 | >**개발 실화** 64 | > 65 | > 실제 애플리케이션에 스토리 보드를 사용하지 않고 Today Widget을 생성해 본 경험에 의하면 단순히 위와 같이 key-value를 수정하는 것 외에, 사용하려는 `view controller`의 상단에 `@objc` 키워드를 추가해야했습니다. 그렇지 않으면 다음과 같은 문구와 함께 애플리케이션 크래쉬를 피할 수 없었죠. 66 | > 67 | > `*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: object cannot be nil` 68 | > 69 | > 애플 문서만 보고 착실하게 따라했다가 아까운 시간을 얼마나 날려버렸는지...번역하면서 왠지 화가나는 포인트였습니다. 애플 문서에 왜 설명이 자세히 나와있지 않은지, 왜 `@objc`가 필요한지에 대해 한참동안 고민해본 결과🤔, *애플이 이런 방식으로 스토리보드를 사용하게 하는구나...*라는 추론에 이를 수 있었답니다 . 70 | > 71 | > **결론** 72 | > 73 | > 스토리 보드를 사용하지 않으려면 `import` 아래에 `@objc (TodayViewController)`를 반드시 추가해주세요. (Xcode8, Swift3 기준) 74 | 75 | ## UI 디자인 76 | > **IMPORTANT** 77 | > 최상의 결과를 위해 Today Widget 디자인시 오토 레이아웃(Auto Layout)을 사용하십시오. (*MJ: 저는 오토 레이아웃 사용하지 않았는데, 최상의 결과는 아닐 수 있지만 별 문제는 없었어요 :)*) 78 | 79 | Today 화면의 공간이 제한적이기 때문에 위젯을 너무 크게 생성하면 안됩니다. iOS와 macOS 두 플랫폼 모두 위젯의 너비는 Today View의 너비에 맞아야하며, 필요에 따라 높이는 높아질 수 있습니다. 80 | 81 | Xcode에서 제공하는 Today Extension의 템플릿은 기본 여백 insets값을 Auto Layouts로 포함하고 있습니다. Insets값을 확인하기 위해서는 NCWidgetProviding 프로토콜의 `widgetMarginInsetsForProposedMarginInsets:` 메서드를 이용하면 됩니다. 기본으로 제공되는 공간 안에 모든 위젯 컨텐츠를 담아야 합니다. 위젯의 모양에 대해 더 깊이 알고 싶다면 [iOS Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/)의 **Today Widgets** 파트를 참고하세요. 82 | 83 | 위젯에서 나타낼 컨텐츠가 많다면, 위젯의 적절한 높이를 맞추기 위해 Auto Layout constraints를 이용할 수 있습니다. 만일 Auto Layout을 사용하지 않는다면 아래와 같이 `UIViewController`의 `preferredContentSize` 속성을 이용하면 됩니다. 84 | 85 | ``` Objective-C 86 | - (void)receivedAdditional Content { 87 | self.preferredContentSize = [self sizeNeededToShowAdditionalContent] 88 | } 89 | ``` 90 | 91 | **iOS** 위젯 화면 크기가 재조정될때 애니메이션 효과를 주고 싶다면 `animateAlongsideTransition:completion:` 를 이용해 `viewWillTransitionToSize:withTransitionCoordinator:`를 구현하십니오. 92 | 93 | Today view에서 아이템이 나타날때 진동 효과를 사용하려면 `notificationCenterVibrancyEffect`을 사용하세요. 94 | 95 | **mac OS** 위젯은 `NSAppearanceNameVibrantDark`을 상속 받습니다. 기본값을 사용하면 자동적으로 적절한 형태를 갖추게 됩니다. 커스텀 컬러를 사용하려면 어두운 색에서 잘 보이는 색을 선택하도록 하십시오. 96 | 97 | ## 컨텐츠 업데이트 98 | Today Extenstion은 위젯의 상태와 컨텐츠 업데이트를 관리하는 API를 제공합니다(API에 대해 더 알아보려면 [Notification Center Framework Reference](https://developer.apple.com/documentation/notificationcenter)를 참고하세요). Today API는 플렛폼에 따라 약간의 차이는 있지만, 지원되는 기능은 iOS와 macOS에서 거의 유사합니다. 99 | 100 | 위젯을 최신 상태로 보여주기 위해, 시스템은 때때로 위젯 뷰의 스냅샷을 캡처합니다. 위젯이 보여질때 화면이 최신 상태를 반영하기 까지 시스템이 가장 최신 스냅샷을 보여줍니다. 101 | 102 | 스냅샷이 찍히기 전에 위젯의 상태를 업데이트 하려면 `NCWidgetProviding` 프로토콜을 준수하십시오. 위젯이 `widgetPerformUpdateWithCompletionHandler:` 호출을 받으면 위젯이 최신 내용으로 업데이트 되고, 아래 업데이트 결과중 하나와 함께 completion handler를 호출하게 됩니다. 103 | 104 | **업데이트 결과** 105 | 106 | * NCUpdateResultNewData—새로운 컨텐츠가 필요한 경우 107 | * NCUpdateResultNoData—업데이트할 필요가 없는 경우 108 | * NCUpdateResultFailed—업데이트 중 오류가 발생한 경우 109 | 110 | ## 위젯이 나타날 시점 결정하기 111 | Today view에서 위젯이 특정 시점에만 보여져야 한다면(새로운 내용이나 중요한 내용이 있을때) `NCWidgetController` 클래스의 `setHasContent:forWidgetWithBundleIdentifier:` 메서드를 사용하십시오. 이 메서드를 사용하면 위젯 컨텐츠의 상태를 선언하여 시스템이 위젯을 보일지 숨길지 결정하도록 합니다. 112 | 113 | 위젯에 내용이 없음을 선언하고 숨기려면, `setHasContent:forWidgetWithBundleIdentifier:` 메서드를 호출하고 `flag` 파라미터 값을 `false`로 지정하십시오. 컨텐츠 나타내기 위해 위 메서드의 `flag` 파라미터의 값으로 `true`가 전달되기 까지 Notification Center는 위젯을 나타내지 않을 것입니다. 114 | 115 | ## Containing App 열기 116 | 위젯을 이용해 containig app(위젯과 연결된 본 애플리케이션)을 열어야 할때가 종종 있습니다. 예를 들어 캘린더 위젯에서 사용자가 이벤트를 터치하면 캘린더 애플리케이션으로 연동됩니다. 사용자가 선택한 작업과 동일한 부분의 containing app을 실행하기 위해서 애플리케이션과 위젯에서 함께 사용하는 `custom URL scheme`를 활용해야합니다. 117 | 118 | 위젯은 containing app에게 실행하라고 직접적으로 말하지 않습니다. `NSExtensionContext`의 `openURL:completionHandler:` 메서드를 통해 시스템에게 containing app을 실행시키라고 하며, 시스템은 유효성을 판단한 뒤 애플리케이션을 실행합니다. 119 | 120 | ## 수정 모드 지원(macOS) 121 | macOS에서 수정 모드를 지원하려면 ` NCWidgetProviding` 프로토콜을 준수해야합니다. `widgetAllowsEditing` 속성을 `true`로 설정하면 위젯의 헤더 부분에 `Info` 버튼이 자동생성됩니다. 수정모드를 지원하기 위해 `NCWidgetProviding` 프로토콜을 준수하면 수정 모드에 진입 했을때 `Edit`, `Done` 그리고 `Cancel` 버튼을 자동 제공합니다. 122 | 123 | 위젯의 수정 모드/비수정 모드 변화를 파악하려면 `NCWidgetProviding` 프로토콜의 `widgetDidBeginEditing`와 `widgetDidEndEditing` 메서드를 사용하십시오. 124 | 125 | 사용자가 위젯에서 수정을 하는 동안 검색 UI(search view controller)를 보여주려면, `NSViewController`의 `NCWidgetProvidingPresentationStyles` 카테고리를 사용하십시오. 사용자가 검색을 완료했음을 알리면 `dismissViewControllerAnimated:completion:` 메서드를 이용해 search view controller를 숨기십시오. 126 | 127 | ## 위젯 테스트 128 | **iOS** iOS 시뮬레이터나 기기에서 위젯을 테스트 할 수 있습니다. 129 | 130 | **macOS** macOS 위젯을 테스트하는 가장 손쉬운 방법은 Xcode Widget Simulator를 사용하는 것입니다. 이를 위해 widget target의 scheme에서 Wideget Simulator를 지정하면 됩니다. 131 | 132 | App Extentsion에서의 디버깅에 대해 더 알아보려면 [ Debug, Profile, and Test Your App Extension](https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionCreation.html#//apple_ref/doc/uid/TP40014214-CH5-SW8)를 참고하세요. 133 | 134 | 135 | * 번역 및 정리: 전미정 136 | * 오타/오역 및 다양한 의견에 대한 PR은 언제든지 환영입니다. 137 | -------------------------------------------------------------------------------- /App Programing Guide for iOS(Korean).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # iOS 앱 프로그래밍 가이드 번역문 4 | 5 | **[iOS Programming Guide 원문 바로가기](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html)** 6 | 7 | ## Contents 8 | ### [1. Introduction](#소개) 9 | > 문서의 목적 및 용도 설명 10 | 11 | ### [2. Expected App Behaviors](#앱행동) 12 | > 앱 기본 구동 및 배포에 필요한 리소스, 사용자 개인정보 보호, 앱 지역화(현지화)에 관한 내용 13 | 14 | * Providing the Required Resources 15 | * Supporting User Privacy 16 | * Internationalizing Your App 17 | 18 | ### [3. The App Life Cycle](#앱생명주기) 19 | > iOS 앱 기본 작동 구조 및 앱 생명 주기, 각 주기에서 시행하는 작업내용과 작업시점에 관한 내용 20 | 21 | * The Main Function 22 | * The Structure of an App 23 | * The Main Run Loop 24 | * Execution States for Apps 25 | * App Termination 26 | * Threads and Concurrency 27 | 28 | ### [4. Background Excution](#백그라운드실행) 29 | > 백그라운드 상태로 전환될때 작업 마무리하기, 백그라운드 상태에서 되돌아오기 등 백그라운드 상태와 관련된 내용 30 | 31 | * Executing Finite-Length Tasks 32 | * Downloading Content in the Background 33 | * Implementing Long-Runnig Tasks 34 | * Getting the User's Attention While in the Background 35 | * Understanding When Your App Gets Launched into the Background 36 | * Being a Responsible Background App 37 | * Opting Out of Background Execution 38 | 39 | ### [5. Stragegies for Handling App Stage Transitions](#상태전환) 40 | > 실행, 구동, 백그라운드, 종료, 일시 정지 등과 같은 앱의 실행 상태 변화에 따른 역할과 관련 메소드 사용법에 관한 내용 41 | 42 | * What to Do at Launch Time 43 | * What to Do When Your App Is Interrupted Temporally 44 | * What to Do When Your App Enters the Background 45 | 46 | ### [6. Strategies for Handling App Features](#앱기능) 47 | > 개인정보 활용, 등급제한, 여러 iOS 버전에 대응하기, 앱 상태 보존/복원, VoIP 활용 등 여러가지 앱에서 사용되는 기능에 대한 소개 및 사용법에 관한 내용 48 | 49 | * Privacy Strategies 50 | * Respecting Restrictions 51 | * Supporting Multiple Versions of iOS 52 | * Preserving Your App's Visual Appearance Across Launches 53 | * Tips for Developing a VoIP App 54 | 55 | ### [7. Inter-App Communication](#앱통신) 56 | > iOS에서 이루어지는 앱간의 통신 방법(AirDrop, URLs)에 대한 소개와 데이터 송/수신 방법 57 | 58 | * Supporting AirDrop 59 | * Using URL Schemes to Communicate with Apps 60 | 61 | ### [8. Performance Tips](#성능향상) 62 | > 전력 소모와 메모리 사용 등 앱을 실제로 구동할 때 성능 향상을 위해 고려해야할 여러가지 내용 63 | 64 | * Reduce Your App's Power Consumption 65 | * Use Memory Efficiently 66 | * Tune Your Networking Code 67 | * Improve Your Networking Code 68 | * Improve Your File Management 69 | * Make App Backups More Efficient 70 | * Move Word off the Main Thread 71 | 72 | --- 73 | 74 | 75 | ## [1. Introduction](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007072-CH1-SW1) 76 | >정상적인 앱 구동을 위한 iOS 코어 시스템 및 앱 설계에 관한 문서 77 | 78 | * 본 문서는 iOS 앱을 처음 제작하는 사람들을 위해서가 아니라, 이미 앱을 개발하여 다듬고 향상시키려는 개발자들을 위한 가이드입니다. 79 | * 만약 iOS 개발이 처음이라면 [Start Developing iOS Apps_Swift](https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/index.html#//apple_ref/doc/uid/TP40015214)를 먼저 읽어보세요. 80 | * iOS 기술에 대해 심도있게 알아보려면 [About the iOS Technologies](https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/iPhoneOSTechOverview/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007898)를 참고하세요. 81 | 82 | 83 | ## [2. Expected App Behaviors](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW2) 84 | >Xcode를 이용해 제작된 모든 프로젝트는 즉각 장비에서 구동 될 수 있지만, 그렇다고 App Store에 등록될 준비가 완료된 것은 아닙니다. 모든 앱은 사용자에게 좋은 사용 경험(UX)을 전달하기 위해 어느 정도의 시스템 설정이 필요합니다. 이번 섹션에서는 앱 설계 초기 단계에서 고려해야할 앱의 기본 형태 및 구동에 대해 알아봅니다. 85 | 86 | ### Providing the Requred Resources 87 | >모든 어플은 아래의 리소스 및 메타데이터를 포함해야합니다. 88 | 89 | * 정보 속성 목록 파일(Info.plist) 90 | * 앱 실행 하드웨어 사양 91 | * 한개 이상의 앱 아이콘 92 | * 한개 이상의 앱 런칭 이미지 93 | 94 | #### The App Bundle 95 | >iOS 앱을 생성하게되면 Xcode는 앱을 *bundle*로 묶는데, *bundle*은 앱과 관련된 자원을 그룹화해놓은 파일 시스템의 디렉토리입니다. *bundle*에는 앱 실행 파일, 앱 아이콘, 이미지 파일 및 현지화(localize)된 콘텐츠등의 리소스 파일이 포함되어있습니다. 96 | 97 | * **정보 속성 목록 파일(Info.plist)** : Info.plist 파일은 앱 구성에 관한 중요한 정보가 포함된 구조화된 파일입니다. App Store 및 iOS에서 앱의 기능을 확인하는데 사용되며, 모든 앱이 Info.plist. 파일을 포함해야합니다. 98 | * 기본으로 제공되는 Info.plist 파일에는 필수항목에 대한 기본값이 설정되어있으며, 특정 기능을 위한 항목 추가/변경이 가능합니다. 99 | * Wi-Fi 연결, custom URL 스키마 지원, 사진 앨범 접근등을 위해서는 Info.plist에 적절한 키를 설정해줘야합니다. 100 | * Info.plist의 다양한 키와 값에 대해 자세히 알아보려면 [About Info.plist Keys and Valuse](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009247)를 참고하세요. 101 | 102 | * **앱 아이콘** : 모든 앱은 기기의 홈 화면과 App Store에 표시할 아이콘을 제공해야 합니다. 103 | * 앱 아이콘은 Image Assets에 포함됩니다. 104 | * 아이콘의 크기를 포함하여 아이콘을 디자인 하는 방법에 대한 자세한 내용은 [iOS Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/)을 참고하세요. 105 | 106 | * **런칭 이미지** : 런칭 이미지는 앱을 처음 구동할때 화면에 잠깐 보이는 이미지로, 앱 화면을 구성하고 사용자에게 보여줄 준비가 완료되면 런칭 이미지가 사라집니다. 107 | * 앱이 foregrounde에서 background로 들어갈때는 사용중인 앱의 스냅 샷이 생성되고, 다시 foreground로 되돌아 올대는 런칭 이미지가 아닌 스냅 샷을 활용합니다. 오래도록 앱을 실행하지 않은 경우에는 스냅 샷을 삭제하고 기존의 런칭 이미지를 활용하게 됩니다. 108 | * 런칭 이미지의 크기 및 디자인 방법에 대해서는 [iOS Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/)을 참고하세요. 109 | 110 | --- 111 | 112 | ### Supporting User Privacy 113 | >사용자 개인 정보 보호 및 사용을 위한 앱 설계는 대단히 중요합니다. 대부분의 iOS 장비에는 사용자가 외부에 공개하고 싶지 않은 개인 정보가 포함되어있습니다. 개인 정보를 사용하기 위해서는 반드시 해당 법률에 준수하여 사용자의 동의를 얻은 후에 접근해야합니다. 114 | 115 | * 보호된 데이터 및 리소스의 경우 인증확인 및 요청을 위한 전용 키와 API를 각각 제공합니다. 116 | * 사용자는 접근 권한을 시스템 설정(Setting)에서 언제든지 변경할 수 있으므로, 해당 항목에 접근하기 전에 권한 부여 상태를 확인하십시오. 117 | * 접근시 사용자 권한이 필요한 항목에는 다음과 같은 것이 있습니다. 118 | * 블루투스, 카메라, 달력, 연락처, 건강 정보, 홈킷, 위치정보, 마이크, 기기 모션, 음악, 사진, 미리 알림, 시리, 음성인식, 티비 등 119 | 120 | **\* 중요사항 : 앱에서 보호된 항목에 접근하려고 하면 시스템에서 사용자에게 엑세스 권한을 요청하는 메시지(alert)를 표시합니다. iOS 10 부터는 Info.plist에 각각의 개인 정보를 활용하려는 *목적 문구*를 명시하여 액세스 권한 요청 메시지(alert)에 보이도록 해야합니다.** 121 | 122 | --- 123 | 124 | ### Internationalizing Your App 125 | >iOS 앱은 많은 국가에 배포될 수 있기 때문에 앱 콘텐츠를 지역화하면 더 많은 사용자에게 다가 갈 수 있습니다. 콘텐츠를 현지화하는 과정은 간단한 과정입니다. 126 | 127 | * 지역화 과정을 시작하면 Xcode에서 앱을 현지화 가능한 리소스 파일로 분리하고, 각 리소스를 언어 별 프로젝트(.lproj) 디렉토리를 제공합니다. 128 | * 일반적으로, iOS 앱에서는 다음 유형의 리소스 파일의 현지화가 필요합니다. 129 | * 스토리 보드 파일, 런칭 이미지 파일: 문자열이 포함된 경우 130 | * 오디오 파일: 음성 해설이 포함된 경우 131 | * 언어 별 또는 문화별 컨텐츠가 포함되어 있지 않은 경우 멀티 미디어 파일의 지역화는 하지 않습니다. 132 | 133 | 134 | 135 | ## [3. The App Life Cycle](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW1) 136 | >앱은 작성된 코드와 시스템 프레임 워크간의 정교한 상호작용입니다. 시스템 프레임 워크는 모든 앱의 실행에 필요한 기본 인프라를 제공하며, 개발자는 앱에 어울리는 모양과 느낌을 코드로 구현합니다. 이 둘의 효과적인 상호작용을 위해 iOS 작동원리에 대한 이해가 필요합니다. 137 | 138 | ### The Main Function 139 | > 모든 C 기반의 프로그램과 마찬가지로, iOS 앱의 진입점 역시 main 함수 입니다. iOS에서의 다른 점은 main 함수를 직접 작성하지 않는다는 점입니다. Xcode가 기본 main 함수를 제공해주며, 제공된 main 함수를 수정해서는 안됩니다. 140 | 141 | * main 함수는 UIKit 프레임워크에 제어권한을 넘겨줍니다. UIApplicationMain 함수는 앱의 핵심 객체를 만들고, 스토리 보드 파일로부터 UI를 로드하고, 초기 설정을 위한 코드를 호출하고, 앱의 실행 루프를 동작시킵니다. 142 | * 개발자가 제공해야하는 부분은 스토리 보드파일과 사용자 지정 초기화 코드입니다. 143 | 144 | --- 145 | 146 | ### The Structure of an App 147 | > 앱을 시작하는 동안 UIApplicationMain 함수는 핵심 객체를 설정하고, 앱 실행을 준비합니다. UIApplication 객체는 모든 iOS 앱의 핵심으로, 시스템과 앱 객체 사이의 상호작용을 원활하게 하는 역할을 합니다. 148 | 149 | * iOS 앱은 Model View Controller 아키텍처(MVC 패턴)를 사용합니다. MVC 패턴은 앱의 데이터 부분(혹은 비지니즈 로직)과 이를 어떻게 보여줄지에 대한 부분을 분리합니다. 이러한 패턴은 화면 크기가 다른 다양한 장치에서 앱을 구동하는데 매우 중요한 역할을 합니다. 150 | 151 |
152 | 153 |
154 | 155 | --- 156 | 157 | ### The Main Run Loop 158 | > 앱의 main run loop는 모든 사용자 관련 이벤트를 처리합니다. UIApplication 객체는 실행시 main run loop를 설정하고, 이를 사용해 이벤트를 처리하고 UI 업데이트를 처리합니다. 이름에서 알 수 있듯이, main run loop는 앱의 main thread에서 실행되며, 사용자 이벤트가 입력되면 순차적으로 처리합니다. 159 | 160 |
161 | 162 |
163 | 164 | 165 | * 사용자가 장비와 상호 작용하며 발생된 이벤트는 UIKit에 의해 설정된 특정 포트를 통해 앱에 전달됩니다. 이벤트들은 내부 queue에서 대기하고 있다가 main run loop에 하나씩 전달 됩니다. 166 | * 다양한 유형의 이벤트를 iOS 앱에 전달 할 수 있습니다. 가장 일반적인 이벤트에는 터치, 원격 제어, 모션, 가속도계 및 자이로 스코프 이벤트 등이 있습니가. 각 이벤트에 대한 자세한 내용은 [Event Handling Guid for UIKit Apps](https://developer.apple.com/library/content/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/index.html#//apple_ref/doc/uid/TP40009541)에서 확인 할 수 있습니다. 167 | 168 | --- 169 | 170 | ### Execution States for Apps 171 | > iOS 앱은 언제나 다음 중 하나의 상태값을 지니게됩니다. 172 | 173 | * Not running : 앱이 실행되지 않았거나 혹은 시스템에 의해 종료된 상태 174 | * Inactive : 앱이 foreground에서 실행 중이지만, 일시적으로 이벤트를 받지 못하는 상태 175 | * Active : 앱이 foreground에서 실행 중이며, 사용자 이벤트를 받을 수 있는 상태 176 | * Background : 앱이 백그라운드에서 코드를 실행 중인 상태 177 | * Suspended : 백그라운드에 있는 앱이 더이상 코드를 실행하지 않는 정지된 상태 178 | 179 |
180 | 181 |
182 | 183 | 184 | * iOS 시스템은 전체 시스템에서 발생하는 작업을 처리하며 해당 앱을 여러가지 상태로 이동시킵니다. 예를 들어 사용자가 홈 버튼을 누르거나 전화가 걸려오면 현재 실행 중인 앱이 비활성 상태로 변하게 됩니다. 185 | * 대부분의 상태 전환에는 appDelegate 메소드가 호출 됩니다. 각 메소드를 적절히 사용하면 상태변화에 대응할 수 있습니다. 186 | * `application:willFinishLaunchingWithOptions:` 앱에서 처음으로 코드를 실행 할 수 있습니다. 187 | * `application:didFinishLaunchingWithOptions:` 사용자에게 앱의 화면이 보여지기 전에 마지막으로 초기화를 수행할 수 있습니다. 188 | * `applicationDidBecomeActive:` 앱이 foreground로 전환되는 시점을 알려줍니다. 189 | * `applicationWillResignActive:` 앱이 foreground 상태에서 inactive 되는 시점입니다. 190 | * `applicationDidEnterBackground:` 앱이 background에서 실행되고 있으며, 언제든지 정지될수 있음을 알립니다. 191 | * `applicationWillEnterForeground:` 앱이 background에서 foreground로 진입하고 있지만 아직 active 된 상태는 아닙니다. 192 | * `applicationWillTerminate:` 앱이 종료되고 있음을 알리는 메소드 입니다. 하지만 앱이 시스템에 의해 정지되었을 경우에는 호출 되지 않습니다. 193 | 194 | --- 195 | 196 | ### App Termination 197 | > 앱은 언제든지 종료될 수 있어야 하며, 종료하기 전에 사용자 정보를 저장하거나 특별한 기능을 수행을 위해 기다리지 않습니다. 시스템에 의한 앱 종료는 앱 수명 주기에서 정상적인 부분입니다. 보통은 시스템이 사용하지 않는 메모리를 회수하여 다른 앱을 실행 할 수 있는 공간을 확보하기 위해 종료하지만, 오작동을 하거나 앱이 적절하게 응답하지 않는 경우에도 앱을 종료 시킬 수 있습니다. 198 | 199 | * 시스템에 의해 정지된 앱은 종료 될때 알림을 받지 않지 않고 메모리를 회수당하게 됩니다. 200 | * 사용자가 의도적으로 앱을 종료하는 경우 역시 앱 종료가 앱에 전송되지 않습니다. 201 | 202 | --- 203 | 204 | ### Threads and Concurrency 205 | > 시스템은 기본적으로 앱의 main thread를 생성하는데, 필요에 따라 추가 thread를 생성하여 다른 작업을 수행 할 수 있습니다. iOS 앱의 경우, 직접 thread를 만들고 관리하는 대신 `Grand Central Dispatch(GCD)`, `operation objects`, `asynchronous` 프로그래밍 기법을 사용하는 것이 좋습니다. 206 | 207 | * GCD를 이용하면 수행하고 싶은 작업과, 작업의 순서를 정할 수 있지만, 시스템이 CPU에서 작업을 가장 효과적으로 수행할 수 있는 방법을 결정 할 수 있도록 하는 것이 전반적인 성능을 향상시키고, 코드를 단순화 시킬 수 있습니다. 208 | * Thread와 concurrency(동시성)를 사용할때 다음 사항을 고려하세요. 209 | * View, Core Animation 그리고 UIKit 클래스와 관련된 작업은 main thread에서 실행되어야 합니다. 210 | * 오래 걸리는 작업은 백그라운드 스레드에서 수행해야합니다. 네트워크 작업을 포함하거나, 파일에 접근하거나, 많은 양의 데이터를 처리할 때는 GCD를 이용하여 비동기로 수행해야합니다. 211 | * GCD 및 operation object를 사용한 작업 방법에 대해서는 [Concurrency Programming Guide](https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091)를 참고하세요. 212 | 213 | 214 | ## [4. Background Execution](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1) 215 | > 사용자가 앱을 사용하지 않을 경우 시스템은 앱을 백그라운드 상태로 전환시킵니다. 일반적으로 백그라운드 상태는 정지 상태(suspended)로 가는 길입니다. 앱을 정지 시키는 일을 배터리 수명을 향상 시키는 일이며, 다른 앱이 foreground에서 실행 될수 있는 리소스를 제공해줍니다. 하지만 모든앱이 백그라운드에서 정지되는 것은 아닙니다. 예를 들어 하이킹 앱은 백그라운드에서도 사용자의 위치를 추적해야하며, 오디오 앱은 잠금화면에서도 계속 음악을 재생할 수 있어야 합니다. 이렇게 백그라운드에서 앱을 실행하는 것이 필요하다고 판단되면 iOS는 배터리를 많이 소모하지 않고 효율적으로 수행 할수 있도록 다음과 같은 기술을 제공합니다. 216 | 217 | * foreground에서 짧은 작업을 하는 앱은 백그라운드로 전환될때 해당 작업을 완료할 시간을 요청할 수 있습니다. 218 | * foreground에서 다운로드를 시작하는 앱은 다운로드 관리를 시스템에 전할 할 수 있으므로, 다운로드가 되는 동안 앱이 중지되거나 종료되지 않습니다. 219 | * 특정 유형의 작업을 지원하기 위해 백그라운드에서 실행하는 앱은 하나 이상의 백그라운드 실행 모드에 대한 지원을 선언 할 수 있습니다. 220 | 221 | ### Executing Finite-Length Tasks 222 | > 백그라운드로 이동한 앱이 작업 중인 일을 완료하기 위해 추가적인 시간이 필요한 경우, `UIApplication` 객체의 `beginBackgroundTaskWithName : expirationHandler :` 또는 `beginBackgroundTaskWithExpirationHandler :` 메소드를 호출하여 작업이 완료되기 까지의 추가 시간을 요청 할수 있습니다. 위 메소드 중 하나를 호출하면 앱은 일시적으로 중지가 지연되고, 작업을 마저 실행 할수 있습니다. 작업이 끝난 앱은 `endBackgroundTask:`메소드를 호출하여 시스템에 작업을 마쳤음을 알립니다. 223 | 224 | * `expirationHandler :` 에 종료하기 전에 수행해야하는 코드를 추가 할 수 있지만, 이때 실행되는 작업이 너무 오래 걸리지 않아야합니다. 225 | * 작업을 처리하는데 남은 시간을 알고 싶다면 `UIApplication`의 `backgroundTimeRemaining` 값을 확인하세요. 226 | 227 | --- 228 | 229 | ### Downloading Content in the Background 230 | >파일을 다운로드 할 때는 `NSURLSession` (`URLSession`)객체를 이용해 다운로드를 시작해야 앱이 중지 되거나, 종료 될 경우 시스템에서 다운로드 프로세스를 제어 할 수 있습니다. 백그라운드 다운로드를 지원하는 `NSURLSessionConfiguration` 객체를 통해 작업이 시작되면 적절한 시간에 업로드 또는 다운로드 작업을 시스템에 전달합니다. 231 | 232 | * 앱이 실행중일때 작업이 완료되면 세션 객체는 일반적인 방식으로 `delegate`에 알려줍니다. 233 | * 작업이 끝나지 않은 상태에서 시스템이 앱을 종료하면 시스템은 백그라운드에서 작업을 계속 관리합니다. 234 | * 사용자가 앱을 강제로 종료하면 보류중인 작업이 취소됩니다. 235 | 236 | --- 237 | 238 | ### Implemneting Long-Runnig Tasks 239 | > 구현하는데 많은 시간이 필요한 작업의 경우, 백그라운드에서 실행 될 수있도록 특정 권한을 요청해야합니다. 백그라운드 실행 기능을 위해서는. `Project Setting` - `Capabilities` - `Background Modes` 옵션을 선택해야하며, 이렇게하면 Info.plist 파일에 `UIBackgroundMode` 키가 추가됩니다. iOS에서는 아래와 같은 특정 유형의 기능만 백그라운드에서 실행 할 수 있습니다. 240 | 241 | * 음악 플레이어 앱과 같이 백그라운드에서 사용자에게 미디어 콘텐츠를 재생하는 앱 242 | * 백그라운드에서 오디오 콘텐츠를 녹음하는 앱 243 | * 내비게이션 앱과 같이 항상 사용자에게 위치 정보를 제공하는 앱 244 | * VoIP (Voice over Internet Protocol)를 지원하는 응용 프로그램 245 | * 새로운 콘텐츠를 정기적으로 다운로드하고 처리해야하는 앱 246 | * 외부 액세서리를 정기적으로 업데이트하는 앱 247 | 248 | --- 249 | 250 | ### Getting the User's Attention While in the Background 251 | >알람은 앱이 중지되었거나 백그라운드에 있을때 사용자의 시선을 끌수 있는 방법입니다. 로컬 알림의 사운드, 배지, 알림 기능을 이용하여 사용자에게 알릴 수 있으며 사용자는 앱을 foreground로 되돌려 놓을지 결정해야합니다. 앱이 이미 foreground에서 실행중인 경우, 로컬 알림은 사용자에게 전달되지 않습니다. 252 | 253 | * 로컬 알림을 예약하려면 `UILocalNotification` 클래스의 인스턴스를 만들고 매개변수를 구성한 다음 `UIApplication` 클래스의 메소드를 이용해 일정을 예약 할 수 있습니다. 254 | * 로컬 알림은 알림의 유형(소리, 알림, 배지) 및 알림 시각에 대한 셋팅을 할 수 있습니다. 255 | * `UIApplication` 클래스의 메소드를 사용하여 예약된 알림을 취소하거나 알림 목록을 가져올 수 있습니다. 자세한 내용은 [Local and Remote Notification Programming Guide](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/index.html#//apple_ref/doc/uid/TP40008194)를 참고하세요. 256 | 257 | --- 258 | 259 | ### Understanding When Your App Gets Launched into the Background 260 | >백그라운드 실행을 지원하는 경우, 시스템이 이벤트 처리를 위해 앱을 재실행 시킬 수 있습니다. 사용자에 의해 강제로 앱이 종료되지 않은 이상 다음과 같은 이벤트 중 하나가 발생하면 시스템이 임의로 앱을 재실행하게됩니다. 261 | 262 | * 위치 앱 : 앱에 지정된 특정 지역에 들어왔음을 인지했을때 263 | * 오디오 앱 : 일부 데이터를 처리하기 위해(오디오 재생 혹은 마이크 사용) 264 | * 블루투스 앱 : 연결된 주변 기기에서 데이터를 수신하거나, 중앙으로부터 명령을 받을 때 265 | * 백그라운드 다운로드 앱 : 다운로드를 성공적으로 완료했거나 오류가 발생했을 때 266 | 267 | * 사용자가 강제로 앱을 종료한 경우에는 시스템이 앱을 재실행 하지 않지만, iOS8 이상의 장비에서 위치앱은 재실행됩니다. 268 | * 만일 기기가 비밀번호(지문)으로 보호중이면 사용자가 먼저 기기를 잠금해제 해야 백그라운드 상태에서 앱이 실행됩니다. 269 | 270 | --- 271 | 272 | 273 | ### Being a Responsible Background App 274 | >Foreground 상태의 앱은 시스템 리소스 및 하드웨어 사용과 관련해 항상 백그라운드 상태의 앱보다 우선시 됩니다. 백그라운드에서 실행되는 앱은 이러한 불균등을 대비하여 백그라운드에서 실행될 동작을 준비해야합니다. 특히 백그라운드로 이동하는 앱은 다음 가이드를 준수해야 합니다. 275 | 276 | * **코드에서 OpenGL ES를 호출하지 마십시오.** 백그라운드에서 실행되는 동안 EAGLContext객체를 만들거나 OpenGL ES 드로잉 명령을 실행하면 앱은 즉시 종료됩니다. 백그라운드에서 OpenGL ES를 처리하는 방법에 대해서는 [OpenGL Programming Guide](https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008793)를 참고하세요. 277 | * **앱이 정지 되기 전에 Bonjour 관련 서비스를 취소하십시오.** 앱이 백그라운드로 이동해 정지되기 전에 Bonjour를 취소하고 네트워크 서비스와 관련된 수신 대기 소켓을 닫아야 합니다. 만약 Bounjour 서비스를 직접 취소하지 않으면 시스템이 서비스를 종료시키게됩니다. 278 | * **네트워크 기반 소켓의 연결 오류를 처리 할 수 있도록 준비하십시오.** 시스템은 여러가지 이류로 앱이 정지된 동안 소켓 연결을 해제할 수 있습니다. 신호 손실이나 네트워크 전환 오류에 대비되어있어야 예상치 못한 문제가 발생하지 않습니다. 279 | * **백그라운드로 이동하기 전에 앱 상태를 저장하십시오.** 정지된 앱은 메모리에서 제거되기 전에 앱에 알림이 제공되지 않이 때문에 상태보존 메커니즘을 활용해 앱의 UI 상태를 디스크에 저장해야합니다. 이 기능에 대한 자세한 내용은 [Preserving Your App’s Visual Appearance Across Launches](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforImplementingYourApp/StrategiesforImplementingYourApp.html#//apple_ref/doc/uid/TP40007072-CH5-SW2)을 참고하세요. 280 | * **백그라운드로 이동하기 전에 불필요한 객체에 대한 강한 참조를 해제하세요.** 앱에서 용량이 큰 객체(이미지)를 관리하는 경우, 백그라운드로 이동하기 전에 해당 캐시에 대한 강한 참조를 해제해야합니다. 281 | * **정지되기 전에 공유 시스템 자원 사용을 중지하십시오.** 주소록, 캘린더, 데이터 베이스와 같이 공유 시스템 리소스와 상호작용하는 앱은 정지되기 전에 해당 리소스 사용을 중지해야합니다. 282 | * **View 업데이트를 하지 마십시오.** 앱이 배경에 있을때는 View가 표시되지 않으므로 업데이트를 하지않는 것이 좋습니다. 283 | * **외부 액세서리에 대한 연결 알림 및 연결 해제 알림에 응답하세요.** 284 | * **백그라운드로 이동할 때 활성화된 경고 창을 정리하세요.** 앱을 백그라운드로 전환할때 시스템이 자동으로 `UIActionSheet` 또는 `UIAlertView`를 닫지 않습니다. 백그라운드로 이동하기 전에 적절한 정리를 해야합니다. 285 | * **백그라운드로 이동하기 전에 View에서 민감한 정보를 제거하십시오.** 앱이 백그라운드로 전환되면 시스템은 앱 화면을 스냅 샷으로 찍은 다음, 다시 foreground로 전환 할때 간단히 표시하게 됩니다. `applicationDidEngetBackground:` 메서드에서 돌아오기 전에 비밀 번호나 개인 정보는 숨기도록 해야합니다. 286 | * **백그라운드에 있는 동안 최소한의 작업을 수행하십시오.** 287 | 288 | --- 289 | 290 | ### Opting Out of Backgound Execution 291 | > 백그라운드에서 앱이 전혀 실행하지 않게하려면 Info.plist 파일의 `UIApplicationExitsOnSuspend` 키의 값을 true로 추가하여 백그라운드를 명시적으로 선택해제 할 수 있습니다. 앱이 선택 해제되면 앱 생명 주기가 not-running, inactive, active 상태를 순환하며 백그라운드라 정지 상태로 들어가지 않습니다. 사용자가 홈 버튼을 눌러 앱을 종료하면 `appDelegate`의 `applicationWillTermintae:` 메소드 호출되고 앱이 종료되기 전에 약 5초간 정리되고 not-running 상태로 이동하게됩니다. 292 | 293 | * 백그라운드 실행을 선택해제 하는 것은 권장하지는 않지만, 특정 조건에서는 기본 옵션이 될 수 있습니다. 특히 백그라운드에서 실행되는 코드가 복잡성을 대단히 증가시키는 경우 앱을 종료시키는 것이 간단한 해결책일 수 있습니다. 294 | * 앱이 많은 메모리를 소비하고, 쉽게 메모리를 해제 할 수 없는 경우 시스템이 앱을 빠르게 종료하여 다른 앱을 위한 공간을 확보 할 수 있습니다. 295 | 296 | 297 | ## [5. Strategies for Handling App State Transitions](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html#//apple_ref/doc/uid/TP40007072-CH8-SW1) 298 | > 앱의 실행 상태에 따라 시스템은 어느정도의 기대치를 가지고 있으며, 상태 전환이 발생하면 시스템이 app delegate에게 알림을 줍니다. `UIApplicationDelegate` 프로토콜을 이용해 앱의 상태 변화를 감지하고, 각 상화에 맞는 적절한 대응을 할 수 있습니다. 예를 들어 foreground에서 background로 전환할때 저장되지 않은 데이터를 기록하고, 진행중인 작업을 중지 할 수 있습니다. 이번 세션에서는 상태전환코드를 어떻게 구현하면 좋을지에 대한 팁과 지침을 제공합니다. 299 | 300 | ### What to Do at Launch Time 301 | > 앱이 시작되면(launched) app delegate의 `application:willFinishLaunchingWithOptions:` 와`application:didFinishLaunchingWithOptions:` 메소드를 사용해 다음과 같은 작업을 할 수 있습니다. 302 | 303 | * 앱이 시작된 이유에 대한 정보를 확인하고, 적절하게 대응하십시오. 304 | * 앱의 중요한 데이터 구조를 초기화 하십시오. 305 | * 앱으로 보여줄 Window 및 view를 준비하십시오. 306 | 307 | * 앱이 시작 될때 시스템은 자동으로 `main stroyboard`와 `initial view controller`를 로드합니다. 308 | * `state restoration`(상태복원)을 지원하는 앱의 경우 `willFinishLaunchingWithOptions :` `application : didFinishLaunchingWithOptions :` 두가지 메소드를 이용해 이전 상태 인터페이스로 복원합니다. 309 | * 위 두가지 메소드에서 실행되는 작업은 가능한 가벼워야합니다. 310 | * 앱은 초기화 작업은 5초 이내에 완료되어야 하며, 초기화 작업이 너무 오래 걸리면 시스템이 응답없음으로 간주하고 앱을 종료시킬 수 있습니다. 311 | * 실행 속도를 늦출 수 있는 작업(네트워크 액세스)은 보조 thread에서 실행 되도록 조정해야합니다. 312 | 313 | #### The Launch Cycle 314 | * 앱이 foreground 상태로 들어올때 시스템이 main thread를 생성하고 앱의 main 함수를 호출합니다. 기본 main 함수는 UIKit 프레임워크를 제어하고, 앱이 구동되는데 필요한 초기화 작업을 해줍니다. 315 | * 앱이 background 상태로 시작할때는 foreground 상태로 시작될때와 실행주기에 약간의 차이가 생기는데, 가장 큰 차이점은 작업을 처리한 뒤, 정지(suspend) 될 수 있다는 점입니다. 백그라운 상태로 실행될때에도 시스템은 UI 파일을 로드하지만, 사용자 화면에 표시하지는 않습니다. 316 | * 앱이 어느 상태로 시작되는지 확인하려면 `UIApplication` 객체의 `applicationState` 속성값을 확인해 보면 알 수 있습니다. 317 | 318 | #### Launch in Landscape Mode 319 | * 일반적으로 앱은, 세로 모드로 실행되며 필요한 경우 기기 방향에 맞게 인터페이스를 회전합니다. 만약 가로 방향만 사용하려면 다음과 같은 작업을 수행하여 시스템에 가로 방향으로만 앱이 실행되도록 설정해야합니다. 320 | * Info.plist에 `UIInterfaceOrientation` 키를 추가하고 값을 `UIInterfaceOrientationLandscapeLeft` `UIInterfaceOrientationLandscapeRight` 둘 중 하나로 설정하세요. 321 | * `layout`이나 `autosizing` 옵션이 설정되어있는지 확인하세요. 322 | * `shouldAutorotateToInterfaceOrientation:` 메소드가 `true`를 반환하도록 오버라이드 하세요.(세로모드일 경우 `false`) 323 | 324 | #### Installing App-Specific Data Files at First Launch 325 | * 앱의 구동에 요구되는 데이터나 설정 값 셋팅을 위해 첫 실행 주기(first launch cycle)를 이용할 수 있습니다. 326 | * 앱의 특정 데이터 파일은 Library/Application Support//directory에 위치해야합니다. 327 | * 앱 번들 내에 있는 파일은 code signed 되어있어 수정을 할 수 없기때문에, 만약 수정이 필요한 경우에는 반드시 해당 파일을 샌드박스의 다른 폴더로 복사한 다음 수정해야합니다. 328 | 329 | 330 | --- 331 | 332 | ### What to Do When Your App Is Interrupted Temporaily 333 | > 시스템 알림이 전달되면 앱은 일시적으로 제어권을 잃게되고, 사용자 터치 이벤트를 받아 들이지 않습니다. 이러한 상황을 대비해 앱은 `applicationWillResignActive` 메소드에서 아래와 같은 작업을 수행해야 합니다. 334 | 335 | * 데이터 및 상태를 저장합니다. 336 | * 타이머 및 기타 주기적 작업을 중지합니다. 337 | * 메타데이터 쿼리를 모두 중지합니다. 338 | * 새로운 작업을 시작하지 않도록 합니다. 339 | * 동영상 재생을 중지합니다.(AirPlay를 통한 재생은 제외) 340 | * OpenGL ES 프레임 속도를 재조절합니다. 341 | 342 | * 앱이 일시 정지 상태에서 벗어나 다시 활성 상태로 되돌아 오면 `applicationWillResignActive:` 메소드에서 했던 작업들을 `applicationDidBecomeActive:` 메소드에서 되돌려야합니다. 343 | * 만약 앱에 `NSFileProtectionComplete` 옵션으로 보호된 파일이 있다면, 화면이 잠겨있는동안 해당 파일에 접근하지 못하도록 `applicationWillResignActive:` 메소드에서 해당 파일에 대한 참조를 닫아줘야합니다. 344 | 345 |
346 | 347 |
348 | 349 | 350 | ### What to Do When Your App Enters the Foreground 351 | >Foreground로 들어가면 백그라운드 상태로 이동하면서 중지된 작업을 재개할 수 있습니다. `applicationDidEnterBackground :` 메소드에서 수행 된 작업을 `applicationWillEnterForeground` 메소드에서 실행취소해야하며 `applicationDidBecomeActive:` 메소드는 실행때와 동일한 작업을 계속 수행할 수 있도록 해야합니다. 352 | 353 | * `UIApplicationWillEnterForegroundNotification` 알림을 이용해 앱이 foreground로 다시 들어오는 때를 추측 할 수있습니다. 354 | 355 | #### Be Prepared to Process Queued Notifications 356 | * 정지 상태의 앱이 foreground 또는 background 실행 상태가 될때, 대기 중인(queued) 알람을 처리할 준비가 되어야합니다. 앱이 정지되어 있는 동안에는 앱이 코드를 실행하지 못하므로, 시스템이 관련 알람을 대기열에 추가해두고 코드 실행이 시작되는 순간 앱에 알람을 전달합니다. 357 | * 앱에 전달되는 알람의 내용과 키에는 아래와 같은 것이 있습니다. 358 | * 악세서리 연결 등록 / 연결 해제(`EAAccessoryDidConnectNotification`, `EAAccessoryDidDisconnectNotification`) 359 | * 기기 화면 방향 전환(`UIDeviceOrientationDidChangeNotification`) 360 | * 다량의 시간 변화(`UIApplicationSignificantTimeChangeNotification`) 361 | * 배터리 상태 및 잔량 변화(`UIDeviceBatteryLevelDidChangeNotification`, `UIDeviceVatteryStateDidChangeNotification`) 362 | * 근접 상태 변화(`UIDeviceProximityStateDidChangeNofitication`) 363 | * 보호된 파일의 상태 변화(`UIApplicationProtectedDataWillBecomeUnavailable`, `UIApplicationProtectedDataDidBecomeAvailable`) 364 | * 외부 화면 연결 / 연결 해제(`UIScreenDidConnectNotification`, `UIScreenDidDisconnectNotification`) 365 | * 화면의 스크린 모드 변화(`UIScreenModeDidChangeNotification`) 366 | * Settings에서 변경 가능한 앱 설정값의 변화(`NSUserDefaultsDidChangeNotification`) 367 | * 사용 언어 및 지역 변경(`NSCurrentLocaleDidChangeNotification`) 368 | * 사용자 iCloud 계정 변경(`NSUbiquityIdentityDidChangeNotification`) 369 | 370 | * 대기 중인 알람(queued notification)은 사용자 터치나 입력 전에 앱의 main run loop로 전달됩니다. 371 | * 앱이 재개 될때 눈에 띄는 지체가 발생하지 않도록 이러한 이벤트를 빠르게 처리 할 수 있어야합니다. 372 | 373 | #### Handle iCloud Changes 374 | * iCloud 상태 변화에 따라 앱은 iCloud 관련 UI를 업데이트하거나, 관련문서에 대한 참조 상태를 변경해야합니다. 375 | * 앱에서 iCloud 사용 여부를 묻는 메시지가 이미 표시되는 경우, iCloud 상태가 변경되었다고 해서 다시 메시지를 띄우지 마십시오. 관련된 설정은 앱 환결 설정이나, 시스템 Settings에서 사용자가 지정 할수 있도록 하십시오. 376 | 377 | #### Handle Locale Changes 378 | * 앱이 일시 정지된 상태에서 사용자가 Locale(지역)을 변경하면 날짜, 시간 및 숫자와 같은 정보를 강제 업데이트 할 수 있습니다. 379 | * Locale 변경에 대등하기 위한 코드 국제화와 관련된 자세한 내용은 [Internationalization and Localization Guide](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/Introduction/Introduction.html#//apple_ref/doc/uid/10000171i)를 참고하세요. 380 | 381 | #### Handle Changes to Your App's Settings 382 | * Settings를 통해 관리되는 설정값이 있다면 `NSUserDefaultsDidChangeNotification` 알람을 확인해야 합니다. 앱이 일시 정지되거나, 백그라운드 상태일때 설정을 수정할 수 있으므로 해당 알람을 사용하면 설정 변경에 따른 적정한 반응을 할 수 있습니다. 383 | * 경우에 따라 해당 알림에 응답하는 것은 잠재적인 보안 허점을 줄일 수 있습니다. 암호 또는 기타 보안 관련 정보가 변경된 경우 인터페이스를 적절히 업데이트 해야합니다. 384 | 385 | --- 386 | 387 | ### What To Do When Your App Enters the Bakcground 388 | > Foreground에서 백그라운드로 이동할때는 `applicationDidEnterBackground:` 메소드를 사용하여 다음과 같은 작업을 수행할 수 있습니다. 389 | 390 | * 앱 스냅샷 준비 391 | * 메모리 확보 392 | 393 | * `applicationDidEnterBackground:` 메소드는 약 5초 동안 모든 작업을 수행하게 되는데, 작업 수행 이내에 메소드가 return 되지 않으면 앱에 종료되고 메모리에서 제거됩니다. 394 | * 작업 수행에 더 많은 시간이 필요한 경우 `beginBackorundTaskWithExpirationHandler:` 메소드를 호출하여 백그라운드 실행 시간을 요청한 다음, 보조 스레드에서 장시간 작업을 수행합니다. 395 | * 백그라운드 작업을 시작하는지 여부에 관계없이 `applicationDidEnterBackground:` 메소드는 5초 이내에 종료되어야 합니다. 396 | 397 | #### The Background Transition Cycle 398 | * 사용자가 홈 버튼을 누르거나, Sleep/Wake 버튼을 눌렀을 때, 시스템에 다른 앱을 실행 시킬때 foreground에 있던 앱을 비활성 상태(inactive state)가 되었다가 백그라운드 상태로 진입하게 됩니다. 이러한 상태 변화는 `applicationWillResignActive:` 와 `applicationDidEnterBackground:` 메서드를 호출하게 됩니다. 399 | * 대부분의 앱은 `applicationDidEnterBackground:` 메소드가 호출 되고, 잠시후 일시 중지 상태로 전환됩니다. 400 | 401 |
402 | 403 |
404 | 405 | #### Prepare for the App Snapshot 406 | * app delegate의 `applicationDidEnterBackground:` 메소드가 반환 되고 잠시 후 시스템은 앱의 화면을 스냅샷을 촬영합니다. 407 | * 백그라운드 작업 수행이 진행되어 화면에 변화가 생기면, 시스템은 스냅샷에 변화 사항을 반영합니다. 408 | * 촬영된 스냅샷은 멀티 태스킹 UI에 사용됩니다. 409 | * 백그라운드에 진입할때 view에 변화를 주는 경우, `snapshotViewAfterScreenUpdates:` 메소드를 호출하여 변경 사항을 렌더링 할 수 있습니다. 410 | * `snapshotViewAfterScreenUpdates:` 메소드의 매개변수를 `true` 값으로 설정하면 강제로 스냅샷을 업데이트 합니다. 411 | 412 | #### Reduce Your Memory Footprint 413 | * 시스템은 최대한 많은 메모리를 유지하려고 시도하며, 메모리가 부족한 경우에는 일시 중지된 앱을 종료하여 메모리를 회수합니다. 414 | * 백그라운드에서 대용량의 메모리를 사용하는 경우, 종료 1순위 대상이 됩니다. 415 | * 백그라운드에 들어갈때, 앱은 더 이상 필요없는 개체에 대한 강한 참조를 해제해야합니다. 416 | * 가능한 빨리 강한 참조를 해제해야 하는 객체에는 아래와 같은 예가 있습니다. 417 | * 생성한 이미지 객체 418 | * 디스크에서 다시 로드할 수 있는 대형 미디어 또는 데이터 파일 419 | * 앱에 당장 필요하지 않으며, 나중에 쉽게 다시 만들 수 있는 모든 객체 420 | 421 | 422 | ## [6. Strategies for Implementing Specific App Features](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforImplementingYourApp/StrategiesforImplementingYourApp.html#//apple_ref/doc/uid/TP40007072-CH5-SW1) 423 | >각각의 앱은 서로 다른 기능과 필요성을 지니지만, 일부 특징은 다양한 앱에는 공통적입니다. 이번 섹션에서는 특정 유형의 기능을 어떻게 앱에서 구현할 수 있는지에 대한 가이드라인을 제시합니다. 424 | 425 | ### Privacy Strategies 426 | > 사용자의 개인 정보를 보호하는 것은 앱을 디자인할때 고려해야할 주요사항 입니다. 보호되어야 할 개인정보에는 사용자의 신원 및 개인 정보와 사용자의 데이터가 포함됩니다. 시스템 프레임워크는 연락처와 같은 데이터를 관리하기 위해 개인 정보 제어를 기본적으로 제공하지만, 앱은 로컬에서 사용하는 데이터를 보호하기위해 개별 적인 조치를 취해야 합니다. 427 | 428 | #### Protecting Data Using On-Disk Encryption 429 | > 데이터 보호는 내장된 하드웨어에 암호화 된 형식으로 파일을 저장하고, 필요할때 암호를 해독하는 방식을 사용합니다. 사용자긔 기기가 잠겨있는 동안에는 해당 파일을 만든 앱도 파일에 접근 할 수 없습니다. 데이터 보호는 대부분의 iOS 기기에서 사용할 수 있습니다. 430 | 431 | * 파일을 보호하려면 원하는 보호 수준을 나타내는 속성을 파일에 추가하십시오. 432 | * `NSData` 클래스 또는 `NSFileManager`클래스를 사용하여 보호 여부를 지정할 수 있습니다. 433 | * `NSData`의 `writeToFile: options: error:` 메소드를 사용하여 새로 작성하는 파일에 보호 설정을 할수 있습니다. 434 | * `NSFileManager` 의 `setAttributes: ofItemAtPath: error:` 메소드를 사용해 기존 파일의 보호 값을 설정 할 수 있습니다. 435 | * 모든 개체는 `UIApplication`의 `protectedDataAvailable` 속성 값을 검사하여 현재 파일에 접근이 가능한지 여부를 확인 할수 있습니다. 436 | * 새롭게 작성하는 파일의 경우, 데이터를 작성하기 전에 보호하는 것이 좋습니다. 437 | 438 | #### Identifying Unique Users of Your App 439 | > 앱에서 사용자를 식별하는 작업을 수행 할때는 항상 투명하게 작업해야합니다. 사용자를 식별하는데 사용되는 몇가지 방법에는 다음과 같은 방법이 있습니다. 440 | 441 | * 사용자 정보로 로그인하는 화면을 구현해 서버의 특정 계정에 연결합니다. 442 | * `UIDevice`의 `identifierForVendor` 속성을 이용해 서로다른 장치 사용자를 구분합니다. 443 | * 광고 목적으로 사용자를 식별하기 위해서는 `ASIdentifierManager` 클래서의 `advertisingIdentifier` 값을 이용해 사용자 ID를 확보 할 수 있습니다. 444 | 445 | --- 446 | 447 | ### Respecting Restrictions 448 | > 사용자는 앱에 사용되는 미디어의 등급을 지정하여 제한 설정할 수 있습니다. 만약 앱이 미디어를 포함하거나 수정하는 경우, 제한 설정을 확인하고 그 변경사항에 맞는 응답을 해야합니다. 449 | 450 | * 제한 설정 값을 가져오려면 `standardUserDefaults` 객체의 `objectForKey`메서드를 사용해 각 값을 확인 할 수 있습니다. 451 | * `com.apple.content-rating.ExplicitBooksAllowed` 452 | * `com.apple.content-rating.ExplicitMusicPodcastsAllowed` 453 | * `com.apple.content-rating.AppRating` 454 | * `com.apple.content-rating.MovieRating` 455 | * `com.apple.content-rating.TVShowRating` 456 | * `objectForKey`가 위 특정 키에 대해 `nil`을 반환하면 해당 정보를 사용할 수 없음을 의미합니다. 이런 경우에는 앱 자체 정책을 사용하여 적절한 등급을 결정 할 수 있습니다. 457 | 458 | --- 459 | 460 | ### Supporting Multiple Versions of iOS 461 | > 최신버전의 iOS와 이전 버전을 함께 지원하는 앱의 경우, 이전 버전의 iOS에서 최신 API를 사용하지 못하도록 런타임 검사를 실시해야합니다. 런타임 검사는 현재 OS에서 사용할 수 없는 기능을 사용하려고 할때 발생하는 앱 충돌(crash)를 방지해줍니다. 462 | 463 | * 해당 class가 존재하는지 검사하기 위해 Class 객체가 nil인지 아닌지 확인하는 방법이 있습니다. 464 | * 해당 메소드를 사용할 수 있는지 확인하기 위해 `instancesRespondToSelector:` 또는 `respondsToSelector:`를 사용할 수 있습니다. 465 | * 여러가지 대상을 지원하는 코드를 작성하는 방법에 대해서는 [SDK Compatibility Guide](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Introduction/Introduction.html#//apple_ref/doc/uid/10000163i)를 참고하세요. 466 | 467 | --- 468 | 469 | ### Preserving Your App's Visual Appearance Across Launches 470 | > 백그라운드로 전환된 앱은 현재 foreground에서 구동되는 앱의 메모리 확보를 위해 언제든지 시스템에 의해 종료 될수 있습니다. 하지만 사용자는 앱을 전환하거나 할때 앱이 일시 종료되었다고 생각하고, 완전히 종료되었다고 생각하지 않기 때문에 마지막 사용시점으로 되돌아오는 것이 좋습니다. 이러한 동작은 사용자에게 더 나은 UX를 제공할 수 있습니다. 이번 세션에서는 iOS의 infrastrucure를 활용해 상태 보존/복원(state preservation, restroration)을 구현 하는 방법을 알아봅니다. 471 | 472 | * `UIKit`의 상태 보존 시스탬은 `View Controller`와 `View`의 상태를 보존, 복원하기 위한 간단하고 유연한 infrastructure을 제공합니다. 473 | * Infrastructure는 적절한 시점에 보존 및 복구 프로세스를 추진합니다. 474 | * 앱의 상태 보존을 위해 고려해야하는 위치는 다음 세가지가 있습니다. 475 | * App delegate 객체 (앱의 최상위 레벨 상태 관리) 476 | * View Controller 객체 (앱의 전반적인 UI 관리) 477 | * Custom Views (보존해야할 custom data가 있는 경우) 478 | 479 | #### Enablikng State Preservation and Restoration in Your App 480 | * 앱의 상태 보존/복원은 자동기능이 아니므로, 앱에서 사용하도록 선택해야합니다. 481 | * App delegate에서 다음 메소드를 구현하여 `true`값이 반환되도록 합니다. 482 | * `application: shouldSaveApplicationState:` 483 | * `application: shouldRestoreApplicationState:` 484 | 485 | #### The Preservation and Restoration Process 486 | > 앱 상태 보존 / 복원 기능을 이용하기 위해서는 앱에서 보존되어야할 객체를 식별해줘야 `UIKit`에서 적절한 시점에 객체를 보존 / 복원하는 작업을 수행 할 수 있습니다. `UIKit` 은 보존 / 복원 프로세스의 많은 부분을 처리하므로, 어떻게 작업을 하는지 알아두면 전반적인 코드 작성과 흐름이해에 용이합니다. 487 | 488 | * 상태 보존 / 복원을 고려할때, 두가지 프로세스를 분리하는 것이 좋습니다. 489 | * 보존: 앱이 foreground와 background를 오고갈때 `UIKit`은 앱의 상태를 적절히 보존합니다. 상태 보존에 필요한 관련 데이터를 암호화된 디스크 상의 파일에 쓰고, 다음번에 앱이 launch될때 `UIKit`이 해당 파일을 찾아 앱 상태 복원 시도합니다. 물론, 이때 파일은 암호화 되어있기 때문에 기기가 잠금해제 되어있는 경우에만 발생합니다. 490 | * 복원: 상태를 복원하는 동안 `UIKit`은 보존 된 데이터를 사용하여 UI를 재구성 하지만, 실제 객체 생성은 코드에 의해 처리됩니다. Storyboard에 접근해 객체를 로드하는 것은 가능하지만, 실제로 어느 객체가 필요한지, 어느 객체가 생성되었는지는 코드를 통해서 알 수 있기 때문입니다. 객체가 생성되면 `UIKit`이 보존해 놓은 자료를 이용해 객체를 초기화 합니다. 491 | * 각각의 상태에서 앱은 다음과 같은 역할을 하게됩니다. 492 | * 보존 493 | * `UIKit`에 상태 보존을 해야한다고 알립니다. 494 | * `UIKit`에 어떤 `ViewController`와 `View`가 보존 될지 알립니다. 495 | * 보존되는 객체에 대한 데이터를 인코딩해야합니다. 496 | * 복원 497 | * `UIKit`에 상태 복원을 해야한다고 알립니다. 498 | * `UIKit`에서 요청한 객체를 제공(생성) 해야 합니다. 499 | * 복원할 객체의 상태를 디코딩하고, 이를 이용해 객체를 이전 상태로 되돌립니다. 500 | * 가장 중요한 부분은 `UIKit`에게 보존 / 복원할 객체를 알려주는 것으로, 관련 코드를 디자인 할때 대부분의 시간을 소비해야합니다. 501 | * 몇몇 `ViewContrller`는 앱의 `main storyboard`에서 자동으로 로드되지만 `push`되거나 `present`되는 `ViewController`들은 접근이 불가능 하기 때문에 `restoreation idientifier`를 지정해줘야합니다. 502 | 503 |
504 | 505 |
506 | 507 | * 보존하려는 `view controller`에 대해 추후 어떤 방식으로 복원될지 결정해야합니다. `UIKit`는 두가지 방식을 제공합니다. App delegate를 이용해 재구성하거나 view controller에 `restoration class` 를 구현하는 방식이 있습니다. 각 방식에 대한 사용팁은 아래와 같습니다. 508 | * 만약 main storyboard를 통해 view controller가 항상 로드된다면, `restore class` 를 구현하지 마십시오. 대신 app delegate를 이용해 객체를 복원하십시오. 509 | * 만약 main storyboard를 통해 view controller가 로드되지 않는다면, `restore class`를 구현하는 것이 좋습니다. 510 | 511 | #### What Happnes When You Exclude Groups of View Controllers? 512 | > 어떤 view controller의 restore identifier가 `nil`이면 해당 view controller와 이의 child view controllers은 보존 데이터에서 제외됩니다. 만일 child view controller를 수동으로 보존하려면 childe view controller에 개별적으로 rester identifier를 지정해주면됩니다. 513 | 514 | #### Checklist for Implementing State Presevtion and Restoration 515 | > 앱의 상태 보존 / 복원을 지원하려면 app delegate와 view controller가 상태 정보를 인코딩/ 디코딩 할 수 있도록 수정해야합니다. 상태 보존 / 복원 기능 추가를 위한 코드 작성시, 아래 체크리스트를 확인하십시오. 516 | 517 | * (필수) `application:shouldSaveApplicationState:`, `application:shouldRestoreApplicationState:`를 구현하십시오. 518 | * (필수) 보존하려는 각각의 view controller의 `restorationIdentifier`에 빈값이 아닌 String값 입력하십시오. 519 | * (필수) `application:willFinishLaunchingWithOptions:` 에서 복원할 스크롤 위치와 관련 UI 설정을 위해 window를 살피십시오. 520 | * 필요하다면 view controller에 `restoration class`를 구현하십시오. 521 | * 보존 / 복원 하려는 view controller 혹은 view에 `encodeRestorableStateWithCoder:`와 `decodeRestorableStateWithCoder:`메소드를 추가하십시오. 522 | * 테이블 뷰나 콜렉션 뷰에서 data soucre역할을 하는 객체는 `UIDataSourceModelAssociation protocol`을 구현해야합니다. 필수사항은 아니지만 이 프로토콜은 해당 뷰에서 선택되거나 보이는 영역의 복원을 도와줍니다. 523 | 524 | #### Enabling State Preservation and Restoration in Your App 525 | > 앱 상태 보존 / 복원을 자동 기능이 아니므로 app delegate에서 아래 두 메소드를 구현해 기능 지원을 명시해야합니다. 526 | 527 | * `application:shouldSaveApplicationState:` 528 | * `application:shouldRestoreApplicationState:` 529 | 530 | #### Preserving the State of Your View Controllers 531 | > View controller의 상태 보존을 위해서는 다음 작업을 해야합니다. 532 | 533 | * (필수) `restore identifier` 할당 534 | * (필수) 앱 실행 시점(launch)에서 새로운 view controller 를 생성할 코드 작성 535 | * (옵션) 앱을 다시 실행했을때 재생성 되지 않는 상태 정보를 위해 `encodeRestorableStateWithCoder:`와 `decodeRestorableStateWithCoder:` 메소드 구현 536 | 537 | #### Preserving the State of Your Views 538 | > 특정 view에 보존할만한 가치가 있는 정보가 있다면, view가 포함된 view controller의 나머지 부분과 함께 보존 될 수 있습니다. view의 상태를 저장하는 경우는 view 자신이 속한 view controller와 독립적으로 사용자가 변경할 수 있는 경우입니다. 예를들어 스크롤뷰는 스크롤의 현재 위치값(position)을 저장하게되는데 이는 view controller는 관심이 없는 값입니다. 뷰의 상태값을 저장하기 위해서는 다음과 같은 작업을 해야합니다. 539 | 540 | * view의 `restoretionIdentifier`값을 할당합니다. 541 | * view가 속해있는 view controller도 유효한 `restorationIdentifier`값을 지녀야합니다. 542 | * tableView와 collectionView의 경우 `UIDataSourceModelAssociation protocol`을 준수하십시오. 543 | 544 | #### Preserving Your App's High-Level State 545 | > view controller와 view에 보존 되는 데이터가 아니라도, 다음 두 메소드를 이용해 앱에 필요한 기타 데이터를 저장 할 수 있습니다. 546 | 547 | * `application:willEncodeRestorableStateWithCoder:` 548 | * `application:didDecodeRestorableStateWithCoder:` 549 | 550 | > 위 메소드는 보존 프로세스의 맨 처음에 호출 되므로 UI의 현재 버전 등과 같은 high-level의 앱 상태를 저장 할 수 있습니다. 551 | 552 | #### Tips for Saving and Restore State Information 553 | > 앱 상태 보존 / 복원을 구현하는 경우 다음 지침을 고려하십시오. 554 | 555 | * **버전 정보를 앱 상태와 함께 인코딩 합니다.** 보존을 할때에는 앱의 현재 UI 버전을 식별할 수 있는 버전 문자열 또는 숫자를 인코딩 하는 것이 좋습니다. 버전 정보는 app delegate의 `application:willEncodeRestorableStateWithCoder:` 메소드에서 인코딩 할수 있으며, `application:shouldRestoreApplicationState:` 메소드가 호출 될때 인코딩 되었던 정보를 확인할 수 있습니다. 556 | * **앱 상태 정보에 데이터 모델 객체를 포함하지 마십시오.** 앱은 iCloud 또는 디스크의 로컬 파일에 데이터를 별도로 저장해야합니다. 상태 복원 메커니즘을 사용하여 데이터 저장시, 복원 작업중에 문제가 발생하면 보존 된 데이터가 삭제 될 수 있습니다. 557 | * **앱 상태 보존은 기존에 디자인된 방식으로 view controller를 사용할 것을 기대합니다.** 앱의 view controller 계층 구조는 기존에 설계된 방식을 유지해야합니다. view controller간의 계층/포함 관계와 상과없이 view를 보여주는 경우 보존 시스템이 보존할 view controller를 제대로 찾아내지 못할 수도 있습니다. 558 | * **모든 view controller를 보존하는 것은 의도에 맞지 않을 수있습니다.** 어떤 경우의 view controller는 보존하는 것이 적절하지 않을 수 있습니다. 예를 들어 사용자의 민감한 정보가 있는 화면은 보존 / 복원하지 않습니다. 559 | * **복원 프로세스 중에 view controller 클래스를 변경하지 마십시오.** 복원 하는 동안 앱의 클래스가 보존했던 객체의 클래스와 일치 하지 않거나 하위 클래스가 아니면 복원 작업을 하지 않습니다. 560 | * **사용자가 강제로 앱을 종료하면 시스템에서 앱의 보존 상태를 자동으로 삭제합니다.** 앱이 종료될때 복원 상태를 삭제하는 것은 일종의 안정 장치입니다. 보존 / 복원 기능을 테스트 하려면 멀티태스킹 상태를 사용하지 말고 Xcode를 이용해 임시 명령이나 제스처로 exit를 호출하도록 하십시오. 561 | 562 | --- 563 | 564 | ### Tips for Developing a VoIP App 565 | > VoIP(Voice over Internet Protocol) 앱을 통해 사용자는 기기의 셀룰러 서비스 대신 인터넷 연결을 이용해 전화를 걸 수 있습니다. iOS 8 이상에서는 APN(Apple Push Notification Serviece) 및 PushKit 프레임 워크의 API를 사용하여 VoIP 앱을 만들 수 있습니다. 푸쉬기능을 기용하면 VoIP 사용을 위한 지속적인 네트워크 연결이나 소켓 구성을 하지 않아도 됩니다. VoIP 푸시가 도착하면 앱이 푸시를 처리할 시간이 주어집니다(앱이 종료된 상태에도). 566 | 567 | * VoIP 구현을 위해 다음과 같은 요구사항들이 있습니다. 568 | * **앱에 VoIP 백그라운드 모드를 사용해야합니다.** Xcode project Capabilities 탭에서 백그라운드 모드를 활성화 합니다. 보통 VoIP 앱은 오디오 내용을 포함하기 때문에 Audio 및 AirPlay 백그라운드 모드도 사용하는것이 좋습니다. 569 | * PushKit API를 사용하여 VoIP 푸시 알림을 수신하고, 수신 알람을 처리하도록 하십시오. 570 | * 오디오 세션을 구성하고 활성화 시키십시오. 571 | * iPhone에서 더 나은 UX를 보장하려면 `Core Telephony` 프레임 워크를 이용하십시오. 572 | * VoIP 백그라운드 모드를 활성화 하면 백그라운드에서 오디오를 재생할 수도 있고, 시스템 부팅 직후 백그라운드에서 재시작 되어 VoIP 서비스를 항상 사용 할수 있습니다. 573 | 574 | 575 | #### Using the Reachability Interfaces to Improve the User Experience 576 | > VoIP 앱은 네크워크 환경에 크게 의존하기 때문에, `System Configuration framework`의 `reachability interface`를 활용해 네크워크 가능성을 확인하고 결과에 맞게 동작을 조정해야합니다. `reachability interface`를 사용하면 네트워크 상태가 변경 될때마다 앱에 알림을 보낼 수 있습니다. 변경 사항을 감지하여 사용자에게 VoIP 연결 상태에 대해 알려주도록 해야합니다. 577 | 578 | * 네트워크 가용성을 파악해 앱의 동작을 조정하면, 기기의 배터리 수명을 향상 시킬 수 있으며 앱이 더 자주 잠자기 상태로 있을 수 있습니다. 579 | * `reachability interface`에 대한 자세한 내용은 [System Configuration Framework Reference](https://developer.apple.com/reference/systemconfiguration)를 참고하세요. 580 | 581 | 582 | ## [7. Inter-App Communication](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW2) 583 | > 기기내 앱간 통신은 간접적인 방식을 통해서만 가능합니다. AirDrop을 사용하여 다른 앱과 파일 및 데이터를 공유 할 수 있습니다. 또한 앱 URL을 사용하여 앱에 정보를 보낼 수 있도록 custom URL Schemes을 정의할 수 있습니다. 584 | > * 참고: `UIDocumentInteractionController` 객체 또는 `document picker`를 사용하여 앱간 파일 교환도 가능합니다. `UIDocumentInteractionController`에 대한 정보는 [Document Ineraction Programming Topics for iOS](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010403)를, `document picker`에 관한 정보는 [Document Picker Programming Guide](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40014451)를 참고하세요. 585 | 586 | ### Supporting AirDrop 587 | > AirDrop을 통해 근처에 있는 기기와 사진, 문서, URL 그리고 각종 데이터들을 공유 할 수 있습니다. AirDrop은 peer-to-peer 네트워킹을 통해 주변 기기를 찾고 연결합니다. 588 | 589 | #### Sending Files and Data to Another App 590 | > AirDrop을 이용해 파일과 데이터를 전송하려면 `UIActivityViewController` 객체를 사용하십시오. `UIActivityViewController`객체를 사용하면 현재 보여지는 UI 화면에 activity sheet를 보여줍니다. 해당 객체를 생성할때 전송하려는 데이터를 지정하십시오. `UIActivityViewController`는 특정 데이터를 지원 가능한 activities만 표시해줍니다. AirDrop의 경우 이미지, 문구, URL 그리고 몇몇 다른 타입의 데이터 전송이 가능합니다. `UIActivityItemSource` 프로토코를 채택한 custom 객체 전송도 가능합니다. 591 | 592 | * 더 많은 정보를 보려면 [UIActivityViewController Class Reference](https://developer.apple.com/reference/uikit/uiactivityviewcontroller)와 [UIActivity Class Reference](https://developer.apple.com/reference/uikit/uiactivity)를 참고하세요. 593 | 594 | #### Receiving Files and Data Send to Your App 595 | > AriDrop을 통해 수신한 파일을 받으려면 아래와 같은 작업을 하십시오. 596 | 597 | * Xcode에서 앱에서 열 수 있는 문서 타입을 명시하십시오. 598 | * app delegate에 ` application:openURL:sourceApplication:annotation:` 메소드를 구현하여 다른 앱을 통해 받은 데이터를 받으십시오. 599 | 600 | * Xcode project Info 탭에 앱에서 지원가능한 문서 타입을 지정할 수 있는 문서 유형 섹션이 있습니다. 문서 유형의 이름과 데이터 유형을 나타내는 하나 이상의 UTI를 지정해야합니다. 예를 들어 png 파일에 대한 지원을 선언하려면 public.png를 UTI 문자열로 포함합닏. iOS는 지정된 UTI를 사용하여 앱이 주어진 문서를 열 수 있는지 확인합니다. 601 | * 문서를 앱 컨테이너에 전송 받게 되면 (필요한 경우)시스템이 앱을 launch 하고 app delegate의 `application:openURL:sourceApplication:annotation:` 메소드를 호출하게 됩니다. 이때 앱이 foreground 상태라면 이 메소드를 사용해 유저에게 파일을 보여주고, background 상태라면 나중에 열 수 있는 파일이 있음을 노트해둬야합니다. 602 | * AirDrop을 통해 전송 된 파일은 암호화 되기 때문에 장치가 잠금 해제 되어있지 않으면 파일을 열 수 없습니다. 603 | * AirDrop을 이용해 전송받은 파일은 앱에서 읽고, 삭제하는 것은 가능하지만 편집은 불가능 합니다. 604 | 605 | --- 606 | 607 | ### Using URL Schemes to Communicate with Apps 608 | > URL scheme을 사용하면 정의해둔 프로토콜을 통해 다른 앱과 통신 할 수 있습니다. Scheme을 구축해둔 앱과 통신 하려면 적절한 형식의 URL를 구성하고 시스템에 열어달라고 요청해야합니다. 특정 sheme을 사용하려면 해당 scheme에 대한 지원여부를 선언하고, 해당 sheme을 통해 들어오는 URLs을 처리해야합니다. 609 | 610 | * Apple은 http, mailto, tel 그리고 sms URL scheme에 대한 내장 지원을 제공합니다. 또한 Maps, YouTube 그리고 iPod 앱을 대상으로 하는 http기반 URL도 지원합니다. 611 | * 기본 scheme에 대한 핸들러는 고정되어있으며 변경 할 수 없습니다. (Apple에서 지원하는 것과 동일한 scheme을 사용하면 시스템에서는 기본 앱을 실행합니다.) 612 | * Apple에서 지원하는 기본 scheme을 확인하려면 [Apple URL Scheme Reference](https://developer.apple.com/library/content/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007899)를 참고하세요. 613 | 614 | #### Sending a URL to Another App 615 | > 앱에 구현해 놓은 custom URL scheme을 이용해 데이터를 보내려면 적절한 URL을 먼저 생성하고 `openURL:` 메소드를 호출 하면 됩니다. 616 | 617 | #### Implementing Custom URL Schemes 618 | > 앱에서 특별한 형태의 URL을 수신 하려면, 해당 URL scheme를 시스템에 등록해야합니다. 앱은 종종 custom URL scheme를 이용해 다른 앱에서 서비스를 이용 할수 있도록 합니다. 예를 들어 지도 앱은 특정 위치를 지도에 표시하기 위한 URL을 지원합니다. 619 | 620 | * Registering Custom URL Schems: 앱에 custom URL을 등록하려면 Info.plist 파일에 `CFBundleURLTypes` 키를 포함하십시오. `CFBundleURLTypes` 키에는 dictionary가 array로 들어가 있습니다. dictionary는 `CFBundleURLName`, `CFBunldeURLSchemes` 키로 이루어져 있습니다. 621 | 622 | * Handling URL Requests: custom URL scheme를 갖는 앱은 전달되는 URLs을 잘 처리 할 수 있어야 합니다. 모든 URLs은 app delegate를 통해 전달 됩니다. 전달된 URLs을 핸들하기 위해 아래 메소드들을 구현해야합니다. 623 | * `application:willFinishLaunchingWithOptions:`, `application:didFinishLaunchingWithOptions:` : 전달 받은 URL에 대한 정보를 파악하고, URL을 오픈할지 결정합니다. 둘 중 하나의 앱이 `false`를 반환하면 핸들링 코드는 호출되지 않습니다. 624 | * `application:openURL:sourceApplication:annotation:` : 전달받은 파일을 열기 위한 메소드입니다. 625 | 626 | #### Displaying a Custom Launch Image When a URL is Opened 627 | > Custom URL schemes을 지원하는 앱은 각 scheme에 custom launch image를 제공 할 수 있습니다. URL을 처리하기 위해 앱을 실행하고 관련 스냅 샷을 사용 할 수 없는 경우 제공한 launch image가 표시됩니다. launch image를 지정하려면 다음 규칙을 사용하는 이름의 png 이미지를 제공하십시오. 628 | 629 | \-\\.png 630 | 631 | * **basename**: Info.plist 파일에 있는 UILaunchImageFile키로 지정된 기본 이미지 이름을 나타냅니다. 632 | * **url_scheme**: URL sheme의 이름입니다. 633 | * **other_modifiers**: 이미지에 덧붙일수 있는 수식어는 [Information Property Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009247)를 참고하십시오. 634 | 635 | 636 | ## [8. Performance Tips](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/PerformanceTips/PerformanceTips.html#//apple_ref/doc/uid/TP40007072-CH7-SW1) 637 | > 앱 설계(design)가 전반적인 성능에 미치는 영향에 대해 개발 각 단계 마다 고려해야합니다. 전력 사용량과 메모리 사용량은 iOS 앱에 매우 중요한 고려 사항이며, 이 외에도 고려할 사항이 많이 있습니다. 이번 세션에서는 개발 프로세스 전반에서 앱 성능을 위해 고려해야할 요소에 대해 설명합니다. 638 | 639 | ### Reduce Your App's Power Cunsumption 640 | > 모바일 기기에서 전력 소모는 항상 이슈입니다. iOS의 전원 관리 시스템은 현재 사용되지 않는 하드웨어 기능을 종료하여 전력을 절약합니다. 아래의 기능 사용을 최적화 하여 배터리 수명을 향상 시킬 수 있습니다. 641 | 642 | CPU, Wi-Fi, 블루투스, 셀룰러 데이터(4G, 3G), 라디오, 위치 시스템, 가속도계, 디스크 643 | 644 | * 앱 최적화의 목표는 최대한 효율적으로 가능한 많은 작업을 수행하는 것입니다. Instruments를 사용하여 앱의 알고리즘을 항상 최적화 해야합니다. 그러나 가장 최적화 된 알고리즘 조차도 기기 배터리에 부정적인 영향을 미칠 수 있으므로 코드를 작성할때 다음 지침을 고려하십시오. 645 | * Polling이 필요한 작업을 하지 마십시오. Polling 작업은 CPU가 잠자기 모드가 되는 것을 방지 합니다. Polling 대신 NSRunLoop 또는 NSTimer 클래스를 사용하여 필요에 따라 작업을 예약하십시오. 646 | * 가능하면 `UIApplication`의 `shared` 객체의 `idleTimerDisabled` 속성을 `false`로 설정하십시오. IdleTimer는 일정 시간 동안 사용되지 않는 기기의 화면을 끄는 기능을 하는데, 앱 화면을 계속 켜둘 필요가 없는 경우 시스템이 종료시킬 수 있도록 하십시오. 647 | * 가능한 작업을 병합하는 것이 좋습니다. 오랜 시간 동안 작은 chunk로 작업을 수행하는 것 보다 한번에 작업을 수행하는 것이 더 적은 전력을 소비하기 때문입니다. 648 | * 디스크에 너무자주 access하지 마십시오. 예를 들어 앱이 상태 정보를 디스크에 저장하는 경우, 상태에 변경이 생길때만 정보를 저장하고 가능하면 변경 사항을 통합하여 너무 빈번하게 변경 사항을 기록하지 않도록 합니다. 649 | * 필요이상으로 빠르게 화면을 그리지 마십시오. 그리기(draw) 작업은 전력이 많이 소모되는 작업입니다. 650 | * `UIAccelerometer` 클래스를 사용하여 가속도계 이벤트를 수신하는 경우, 필요하지 않을때는 이벤트 전달을 비활성화 하십시오. 자세한 내용은 [Event Handling Guide for UIKit Apps](https://developer.apple.com/library/content/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/index.html#//apple_ref/doc/uid/TP40009541)를 참고하십시오. 651 | * 네트워크로 전송하는 데이터가 많을 수록 많은 전력을 소모하게 되며, 네트워트를 사용하는 작업은 전력 소모에 가장 영향을 많이 기치는 작업입니다. 다음 지침을 따르면 네트워크에 소모되는 시간을 최소화 할 수 있습니다. 652 | * 필요한 경우에만 네트워크 서버에 연결하고 해당 서버를 polling하지 마십시오. 653 | * 네트워트에 연결해 작업을 할때는 압축된 데이터 형식을 사용하여 최소량의 데이터를 전송하십시오. 654 | * `NSURLSession` 클래스를 사용하여 여러개의 파일을 업로드하거나 다운로드 할때, 다음 작업을 하기 위해 이전 작업이 완료되기를 기다리지 말고 queue에 추가하십시오. 시스템이 자동적으로 가장 효율적으로 작업을 실행합니다. 655 | * 가능하다면 Wi-Fi를 사용해 네트워크에 연결하십시오. Wi-Fi는 셀룰러보다 전력 소모가 적습니다. 656 | * `Core Location` 클래스를 이용해 위치 데이터를 수집하는 경우, 최대한 빨리 위치 업데이트를 비활성화 하고 distance filter와 accuracy level을 적절한 값을 설정하십시오. 관련된 자세한 내용은 [Location and Maps Programming Guide](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009497)를 참고하십시오. 657 | * Instruments는 전력 관련 정보 수집을 위한 여러가지 계측기가 포함되어 있습니다. 이 계측기를 사용하여 전력 소비에 대한 여러가지 정보와 여러 하드웨어(Wi-Fi, Blutooth, GPS, 디스플레이, CPU 등)에 대한 측정 값을 수집 할 수 있습니다. 658 | 659 | --- 660 | 661 | ### Use Memory Efficiently 662 | > 앱은 가능한 적은 메모리를 사용하여 시스템이 많은 메모리를 확보할 수 있도록 해야합니다. 시스템의 사용가능한 여유 메모리와 앱의 성능에는 직접적인 상관 관계가 있습니다. 사용 가능한 메모리가 적으면 이후 메모리 요청에 따른 작업을 수행할때 문제을 일으킬 가능성이 높습니다. 663 | 664 | #### Obseve Low-Memory Warnings 665 | > 시스템에서 앱에 메모리 부족 경고를 보내면 즉시 응답하십시오. 메모리 부족 경고는 필요없는 객체에 대한 참조를 제거할 수 있는 기회입니다. 이 경고에 대해 응답하다 실패하는 경우 앱이 종료 될 수 있기 때문에 주의해야합니다. 시스템은 아래 API를 사용해 메모리 경고를 앱에 전달합니다. 666 | 667 | * `applicationDidReceiveMemoryWarning:` : app delegate 메소드 668 | * `didReceiveMemoryWarning`: UIViewController 메소드 669 | * `UIApplicationDidReceiveMemoryWarningNotification`: 노티피케이션 670 | 671 | * 이러한 경고를 받으면 불필요한 메모리를 즉시 해제해야합니다. 사용하지 않는 거대 데이터 구조가 있는 경우, 해당 구조를 디스크에 저장하고 메모리에서 사본을 제거하십시오. 672 | 673 | * 참고: iOS 시뮬레이터의 `Simulate Memory Warning` 명령을 사용하여 메모리 부족 상태의 앱 동작을 테스트 할 수 있습니다. 674 | 675 | #### Reduce Your App's Memory Footprint 676 | > 초기에 낮은 설치 공간으로 시작해 추후에 앱을 확장 할 수있습니다. 초기 설치 공간을 줄이는 방식에는 다음과 같은 방법이 있습니다. 677 | 678 | * **메모리 릭(leak) 제거** Instruments를 사용하여 실제 디바이스와 시뮬레이터에서 메모리 릭을 추적하십시오. 679 | * **리소스 파일 줄이기** 리소스 파일을 가능한 작게 만들기 위해 모든 이미지 파일을 압축하십시오. (iOS 앱 기본 이미지 포맷인 PNG 이미지를 압축하려면 pngcrush 도구를 사용하십시오.) 680 | * **속성 목록 파일 줄이기** NSPropertyListSerialization` 클래스를 사용하여 속성 목록을 이진법으로 작성할 수 있습니다. 681 | * **대규모 데이터 관리** 대규모 데이터를 관리하는 경우 `Core Data` 혹은 `SQLite`를 사용하십시오. 이는 전체 세트를 한번에 메모리에 저장하지 않고 대용량 데이터를 효율적으로 관리 할수 있는 방법을 제공합니다. 682 | * **리소스 로드 시점** 실제로 필요할 때까지 리소스 파일을 로드하지 마십시오. 리소스 파일을 미리 가져오는 것은 시간을 절약 시키는 방법처럼 보일 수 있지만, 결국은 앱의 속도를 저하시키게 됩니다. 683 | 684 | #### Allocate Memory Wisely 685 | > 다음은 현명하게 메모리를 할당할 수 있는 팁입니다. 686 | 687 | * **리소스에 크기 제한을 두십시오.** 고해상도 이미지를 사용하는 대신 iOS 기기에 적합한 크기의 이미지를 사용하십시오. 대용량 리소스 파일을 사용해야하는 경우에는 파일의 일부분만 로드하는 방법을 사용하세요.(`mmap`, `munmap`) 688 | * **무제한 문제를 다루지 않도록 하십시오.** 제한이 없는 문제는 많은 양의 데이터 계산이 필요할 수도 있습니다. 앱에서 사용 가능한 메모리보다 문제 해결에 더 많은 메모리가 필요 한 경우 계산을 완료하지 못할 수 있습니다. 689 | 690 | --- 691 | 692 | ### Tune Your Networking Code 693 | > iOS의 네트워킹 스택에는 iOS 기기의 무선 통신을 위한 몇가지 인터페이스가 포함되어있습니다. 주요 인터페이스는 `CFNetwork` 프레임 워크이며, `Core Entity`프레임 워크와 `BSD` 소켓을 기반으로 되어있습니다. 694 | > 네트워크 통신을 위해 `CFNetwork` 프레임 워크를 사용하는 방법에 대한 정보는 [ CFNetwork Programming Guide](https://developer.apple.com/library/content/documentation/Networking/Conceptual/CFNetwork/Introduction/Introduction.html#//apple_ref/doc/uid/TP30001132)와 [CFNetwork Framework Reference](https://developer.apple.com/reference/cfnetwork)를 참고하십시오. 695 | 696 | #### Tips for Efficient Networking Using Wi-Fi 697 | > 네트워크를 통해 데이터를 송수신하는 작업은 기기에서 가장 전력을 많이 소모하는 작업 중 하나입니다. 데이터 송수신에 소요되는 시간을 최소화하여 배터리 수명을 향상시키기 위해 아래 팁을 고려하십시오. 698 | 699 | * 데이터 형식을 가능한 컴팩트하게 정의하십시오. 700 | * 수다스러운 프로토콜 사용을 피하십시오. 701 | * 셀룰러 및 Wi-Fi는 활동이 없을때 자동적으로 꺼지도록 설계되어있지만, 앱이 주기적으로 작은 데이터를 전송하는 경우에는 Wi-Fi가 활동하지 않을때도 계속 켜져 전력을 소비할 수 있습니다. 소량의 데이터를 자주 송신하기 보다 대량의 데이터를 긴 간격으로 전송하는 것이 좋습니다. 702 | * 네트워크 동신을 할때 패킷은 언제든지 손실 될 수 있습니다. 따라서 네트워킹 코드를 작성할때 장애 처리와 관련해서는 강력하게 대응하는 것이 좋습니다. 703 | 704 | #### Using Wi-Fi 705 | > 앱이 Wi-Fi를 사용하여 네트워크에 액세스 하는 경우 앱의 Info.plist 파일에 `UIRequiresPersistentWiFi` 키를 포함시켜 시스템에 알려줘야합니다. 이 키가 포함되어 있으면 앱이 실행되는 동안 Wi-Fi 하드웨어를 종료하지 말아야 한다는 것을 의미합니다. 706 | 707 | #### The Airplane Mode Alert 708 | > 기기가 비행기 모드에 있는 동안 앱이 시작되면, 시스템에서 사용자에게 비행모드임을 알리기 위해 alert를 표시할 수 있습니다. 시스템은 다음 조건이 모두 충족되면 alert를 표시합니다. 709 | 710 | * Info.plist 파일에 `UIRequiresPersistentWiFi` 키가 포함되어있고, 해당 키의 값이 `true`일때 711 | * 기기가 비행기 모드에 있는 동안 앱이 실행됨 712 | * 비행기 모드로 전환 한 후, 장치의 Wi-Fi가 수동으로 활성화 됨 713 | 714 | --- 715 | 716 | ### Imporve Your File Management 717 | > 파일 관리를 위해 디스크에 쓰는 데이터 양을 최소화 하는 것이 좋습니다. 파일 관련 작업을 최소하하는 데 도움이 되는 몇가지 팁은 다음과 같습니다. 718 | 719 | * 파일 전체를 저장하는 것이 아니라, 변경된 파일의 일부분만 저장할 수 있도록 하십시오. 720 | * 데이터가 randomly 접근가능하고, 양이 이 몇 MB이상인 경우 `Core Data` 혹은 `SQLite`와 같은 영구 저장소에 저장하십시오. 721 | * 캐시파일을 디스크에 쓰지 않도록 하십시오. 유일한 예외 상황은 앱을 종료했을때와 동일한 상태로 되돌릴 수 있도록 상태 정보를 저장해야 할때 입니다. 722 | 723 | --- 724 | 725 | ### Make App Backups More Efficient 726 | > 백업은 사용자가 iTunes와 기기를 동기화 할때나 iCloud를 통해 무선으로 실행되고, 백업이 진행되는 동안 기기에서 사용자의 컴퓨터 또는 iCloud 계정으로 파일이 전송됩니다. 앱 샌드박의 파일 위치에 따라 해당 파일을 백업/복원할지 여부가 결정되는데, 앱에서 주기적으로 많은 양의 데이터를 만들고 변경하는 경우에는 백업 속도가 느려질 수 있습니다. 파일 관리 코드를 작성할때는 이 사실을 꼭 염두해 두어야합니다. 727 | 728 | #### App Backup Best Practices 729 | > 백업/복원 작업을 위해 앱에서 준비해야 하는 것은 없습니다. iClound나 iTunes에 연결되면 앱 데이터 파일의 변경된 부분을 백업합니다. 하지만 아래 디렉토리의 내용은 백업하지 않습니다. 730 | 731 | \/AppName.app 732 | \/Library/Caches 733 | \/tmp 734 | 735 | **동기화 프로세스에 걸리는 시간과 앱이 차지하는 용량을 줄이기 위해 다음 가이드 라인에 따라 앱 데이터를 저장하는 것이 좋습니다.** 736 | 737 | * 중요한 데이터는 /Documents 에 저장해야합니다. 중요데이터란 사용자 문서 및 기타 사용자가 생성한 콘텐츠와 같이 앱에서 다시 생성 할 수 없는 데이터입니다. 738 | * Support file에는 앱에서 다운로드하거나 재생성가능한 파일이 포함됩니다. 739 | * 캐시된 데이터는 /Library/Caches 디렉토리에 저장되어야 합니다. 캐시 디렉토리에 저장해야하는 파일의 예로는 데이터베이스 캐시 파일, 잡지, 신문, 지도 앱 등에서 다운로드 받은 파일입니다. 740 | * 임시 데이터는 /tmp 디렉토리에 저장해야합니다. 임시 데이터는 오랜 시간 동안 유지할 필요가 없는 데이터로 구성됩니다. 기기에서 사용된 후에는 공간을 차지하지 않도록 파일을 삭제해야합니다. 741 | * 응용 프로그램에서 디렉토리를 사용하는 자세한 방법은 [File Systeom Programming Guide](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010672)를 참고하세요. 742 | 743 | #### Files Saved During App Updates 744 | > 사용자가 앱 업데이트를 다운로드하면 iTunes는 새로운 앱 디렉토리에 업데이트를 설치합니다. 그런 다음 이전 앱을 삭제하기 전에 사용자 데이터 파일을 새 앱의 디렉토리로 이동시킵니다. 아래 디렉토리의 파일은 업데이트 프로세스에서 보존됩니다. 745 | 746 | \/Documents 747 | \/Library 748 | 749 | **업데이트 후에, 다른 디렉토리의 파일도 옮겨질 수 있지만 파일이 존재한다고 믿어서는 안됩니다.** 750 | 751 | --- 752 | 753 | ### Move Work off the Main Thread 754 | > 앱의 main thread에서 수행되는 작업의 유형을 제한해야합니다. main thread는 앱의 터치 이벤트 및 기타 사용자 입력을 처리하는 곳입니다. 앱이 항상 사용자에게 응답할 수 있도록 하려면 네트워크에 액세스하는 작업이나 장시간이 걸리는 작업을 main thread에서 실행 해서는 안됩니다. 대신 백그라운드 스레드에서 옮겨서 작업해야합니다. 이를 수행하는 가장 좋은 방법은 GCD(Grand Center Dispatch) 또는 NSOperation 객체를 사용하여 작업을 비동기(async)로 수행하는 것입니다. 755 | 756 | * 작업을 백그라운드에서 실행시키면 main thread가 자유롭게 사용자 입력을 처리할 수 있게되며, 이는 앱이 시작/종료될때 특히 중요합니다. 757 | * 앱이 실행(launch)될때 main thread가 차단 된 경우 시스템은 실행이 완료되기 전에 앱을 종료(kill)시킬 수 있습니다. 758 | * 앱이 종료될때 main thread가 차단되어있으면 사용자의 중요한 데이터를 기록하기 전에 시스템이 앱을 종료(kill)할 수 있습니다. 759 | * GCD, operation object, thread에 관한 자세한 정보는 [Concurrency Programming Guide](https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091)를 참고하세요. 760 | 761 | --- 762 | 763 | * 원문에서 중복되는 내용이나 예제 코드는 생략했습니다. 정확한 내용은 [원문](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html)을 확인해주세요. 764 | * **번역: 전미정** 765 | 766 | [**위로가기**](#위로가기) 767 | -------------------------------------------------------------------------------- /Creating Independent watchOS Apps(Korean).md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Creating Independent watchOS Apps 4 | ### 핸드폰 연결없이 단독으로 동작하는 watchOS 애플리케이션 만들기 5 | 6 | **[Creating Independent watchOS Apps 원문 바로가기](https://developer.apple.com/documentation/watchkit/creating_independent_watchos_apps)** 7 | 8 | > 2019년에 발표된 watchOS 6부터 핸드폰과 전혀 상관없이 워치만을 위한 애플리케이션을 개발할 수 있게 되었습니다. 이 문서는 핸드폰과 연동하지 않고 독립적으로 설치, 실행하는 워치 애플리케이션을 개발하는 방법에 대해 소개합니다. 9 | 10 | > 이 문서에서 pair로 연결되는 iOS - watchOS 애플리케이션 관계를 짝(👫) 으로 표현했습니다. 11 | 12 | > 원문을 Xcode 11.4 버전에 맞춰 용어를 업데이트했습니다. 13 | 14 | --- 15 | 16 | 17 | ## 1. Overview 18 | > 애플 워치 사용자들은 핸드폰을 가지고 있지 않을 때에도 워치 애플리케이션이 정상적으로 작동하길 기대합니다. 애플 워치 사용자들에게 최상의 경험을 제공하기 위해 iOS를 필요하지 않는 독립적인 watchOS를 만들어보세요! 19 | 20 | watchOS 프로젝트를 준비하는 방법에는 아래와 같은 2가지 방법이 있습니다. 21 | 22 | 1. **Watch-only app** 23 | : 연결해야하는 iOS 애플리케이션 없이 애플워치에서만 사용할 수 있는 환경을 만들 때 24 | 25 | 2. **WatchOS with iOS app** 26 | : 짝이 되는 iOS 애플리케이션이 있고, iOS 애플리케이션과 유사하거나 연관된 사용자 경험을 watchOS 애플리케이션으로 제공하고 싶을 때 27 | 28 | watchOS 애플리케이션을 만들기 전에 위 두가지 중 어떤 유형으로 생성할지 먼저 결정하세요. 29 | 만일 iOS 애플리케이션과 watchOS 애플리케이션을 짝으로 묶을거라면, watchOS 애플리케이션이 iOS와 어떻게 상호작용할지 분명하게 정해야합니다. 30 | 31 | * **Independent** 독립적인 워치 애플리케이션은 정상적으로 동작하기 위해 iOS 애플리케이션이 필요하지 않습니다. 사용자는 iOS 애플리케이션만 쓸지, watchOS 애플리케이션만 쓸지, 혹은 두 개 다 사용할지 선택할 수 있습니다. 32 | * **Dependent** 짝이있는 워치 애플리케이션은 정상적으로 작동하기 위해 짝 iOS 애플리케이션이 필요합니다. iOS 애플리케이션과의 상호작용이 필요한 경우에만 독립적이지 않은 워치 애플리케이션을 생성하세요. 사용자는 watchOS를 구매하고 설치하기 위해 짝 iOS 애플리케이션을 반드시 함께 구매/설치해야합니다. 33 | 34 | > [참고] watchOS 5 이전 버전의 모든 watchOS 애플리케이션은 반드시 짝 iOS를 필요로합니다 35 | 36 | watchOS 6 이후 버전부터 애플워치에 있는 AppStore에서 watchOS 애플리케이션을 구입하는게 가능합니다(그림1). watchOS 6.2 이후 버전부터는 애플 워치에서 인앱 결재를 하는 것도 가능합니다 💳. 만일 짝 iOS 애플리케이션이 있는 경우 인앱 결재를 하면 watchOS와 iOS에서 모두 해당 컨텐츠 사용이 가능합니다. 자세한 내용은 [인앱 결재 In-App Purchase](https://developer.apple.com/documentation/storekit/in-app_purchase)를 참고하세요. 37 | 38 | ![Appstore on Apple Watch](https://docs-assets.developer.apple.com/published/63fbc6d282/06d45110-1dd7-49a4-a413-9f5159ecdd0e.png) 39 | 그림 1. 애플 워치 속 앱 스토어 40 | 41 | 짝 iOS 애플리케이션이 있는 경우나, 없는 독립적인 경우나 모두 watchOS 애플리케이션을 애플워치에서 바로 다운 받고 설치하는 것은 가능합니다. 하지만 짝 iOS 애플리케이션이 있는 경우에는 핸드폰에 iOS 애플리케이션 설치가 끝날때까지 watchOS 애플리케이션을 작동시킬 수 없습니다. 42 | 43 | 44 | 45 | ## 2. Create a Watch-Only App 46 | > 독립 워치 앱을 생성하는 방법입니다. 47 | 48 | Xcode를 실행하고 `Create a New Xcode Project`를 선택한 뒤 `watchOS`에서 `Watch App` 템플릿을 선택하세요 (아래 그림에서는 `App`이지만 업데이트된 Xcode에서는 `Watch App`으로 변경되었습니다). 49 | 50 | ![figure2](https://docs-assets.developer.apple.com/published/fce218c141/af79db6d-02b1-4df0-9f46-6c3c9db12d76.png) 51 | 그림 2. Watch App 템플릿 선택 52 | 53 | 생성된 프로젝트는 그림 3과 같이 크게 2개의 섹션으로 나뉘어져있습니다 (혹시 3개의 섹션으로 나뉘어져있다면 독립 watch 앱이 아니라 쌍인 iOS 앱이 필요한 경우이니 다시한번 프로젝트를 생성해 보세요). 54 | 55 | 첫번째, **WatchKit app**에는 애플리케이션에서 사용될 스토리보드와 해당 스토리보드에서 사용할 assets 폴더가 포함되어있습니다. 56 | 57 | 두번째, **WatchKit extension**에는 애플리케이션의 코드가 포함됩니다. 58 | 59 | ![image3](https://docs-assets.developer.apple.com/published/d19acfa47f/fa7719ce-5ea2-4292-810e-6c56e722f870.png) 60 | 그림 3. 프로젝트 네비게이션 화면 61 | 62 | 그림 4와 같이 targets은 3개가 생성되는 것을 확인할 수 있습니다. 63 | 64 | ![](https://docs-assets.developer.apple.com/published/52616fcb34/02ac2063-b61c-45ec-963a-f9e6e8f05cbe.png) 65 | 그림 4. 3개의 targets 66 | 67 | 3개의 targets 중 프로젝트를 대표하는 것은 첫번째 target으로, 이를 App Store에 제출하게 됩니다. 나머지 두개의 targets은 각각 WatchKit app과 WatchKit extension을 대표합니다. 68 | 69 | 70 | 71 | ## 3. Convert a Dependent App into an Independent App 72 | 73 | 만일 iOS와 쌍으로 연결하는 애플리케이션을 독립으로 존재하는 워치 애플리케이션으로 변환하고 싶다면 아래와 같이 하면 됩니다. 74 | 75 | 1. 세 가지 targets 중 `WatchKit Extesion`을 선택하고 `General` 탭으로 이동합니다. 76 | 2. 화면 중간 쯤 **Deplotment Info**로 이동합니다. 77 | 3. **Supports Running Without iOS App Installation**을 체크합니다. 78 | 79 | ![](https://docs-assets.developer.apple.com/published/a4dd468172/050ba8c6-8ea7-4a25-88af-0d616fd6b9a7.png) 80 | 그림 5. iOS 짝 애플리케이션 없이 동작 가능하도록 만들기 81 | 82 | Xcode 11 이후 버전 부터는 새로운 watchOS를 만들면 위 체크박스가 기본으로 체크되어있습니다. 83 | 84 | 85 | ## 4. Ensure Your App Runs Independently 86 | > 독립 애플리케이션으로서의 조건에 대해 알아봅시다. 87 | 88 | 독립 애플리케이션은 짝 iOS 애플리케이션이 없어도 정상적으로 작동해야합니다. **정상적인 작동**에는 데이터 다운 받기, 사용자 계정 설정 그리고 애플리케이션 설정 등이 포함됩니다. 89 | 90 | 특히, 독립 watchOS 애플리케이션들은 아래 사항을 만족해야합니다. 91 | 92 | * 애플 워치에서 사용자들의 새로운 계정을 생성하고, 인증 할 수 있어야합니다. 더 자세한 내용은 [Authenticating Users on Apple Watch](https://developer.apple.com/documentation/watchkit/authenticating_users_on_apple_watch)을 참고하세요. 93 | * 시스템 서비스 활용을 위한 사용 권한을 아이폰이 아닌 워치 애플리케이션에서 요청해야합니다. 예를 들어 watchOW 6 이후 버전 부터는 `HealthKit`을 사용하는 애플리케이션은 사용자에게 애플 워치에서 `Health`에 대한 접근 권한을 요청할 수 있습니다. 94 | * 데이터를 워치로 바로 다운로드 받을 수 있어야합니다. 독립 워치 애플리케이션은 iOS 애플리케이션으로 부터 데이터나 파일을 전송받기 위해 **WatchConnectivity**에 의존할 수 없습니다. 만일 디바이스간 데이터 싱크가 필요하다면. *CloudKit*이나 자체 서버를 활용하도록 하세요. 자세한 내용은 [Keeping Your watchOS Content Up to Date](https://developer.apple.com/documentation/watchkit/keeping_your_watchos_content_up_to_date) 95 | * 워치로 push notification을 바로 보내야합니다. 자세한 내용은 [registerForRemoteNotifications()](complication)을 참고하세요. 96 | 97 | iOS 쌍 애플리케이션이 있는 경우에는 iOS 디바이스가 가까이 있을 때 **WatchConnectivity**을 통해 자료를 전달 받을 수 있습니다. 하지만 독립 워치 애플리케이션은 **WatchConnectivity**을 주요 데이터 소스로 사용할 수 없으니 자체 정보에 접근할 수 있는 기능이 구현되어야합니다. 98 | 99 | --- 100 | 101 | * 번역 및 정리: [미정](ninevincentg@gmail.com) 102 | * 오타/오역 및 다양한 의견에 대한 PR은 언제나 환영입니다 🤗 103 | 104 | [**위로가기**](#위로가기) 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # iOS-Programming-Documents 4 | ![Platform](https://img.shields.io/badge/platform-iOS-blue.svg) 5 | ![Language](https://img.shields.io/badge/Language-Swift-red.svg) 6 | ![Language](https://img.shields.io/badge/language-Objective--C-green.svg) 7 | 8 | ### iOS 프로그래밍과 관련된 영어 문서 및 사이트를 한국어로 번역해 놓았습니다. 9 | * 천천히, 조금씩 제가 궁금한 부분 부터 올려보겠습니다. 10 | * 생략된 내용과 코드가 많으니 자세하고 정확한 내용은 각 글의 원문을 참고해주세요. 11 | * 그저 개발을 더 잘하려고 싶어 공부하다 올리게 되었으니 많이 부족하고 오역이 있어도 돌은 던지지 말아주세요. 12 | 13 | # iOS 앱 프로그래밍 가이드 번역문 14 | 15 | **[iOS Programming Guide 원문 바로가기](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html)** 16 | 17 | ## Contents 18 | ### [1. Introduction](#소개) 19 | > 문서의 목적 및 용도 설명 20 | 21 | ### [2. Expected App Behaviors](#앱행동) 22 | > 앱 기본 구동 및 배포에 필요한 리소스, 사용자 개인정보 보호, 앱 지역화(현지화)에 관한 내용 23 | 24 | * Providing the Required Resources 25 | * Supporting User Privacy 26 | * Internationalizing Your App 27 | 28 | ### [3. The App Life Cycle](#앱생명주기) 29 | > iOS 앱 기본 작동 구조 및 앱 생명 주기, 각 주기에서 시행하는 작업내용과 작업시점에 관한 내용 30 | 31 | * The Main Function 32 | * The Structure of an App 33 | * The Main Run Loop 34 | * Execution States for Apps 35 | * App Termination 36 | * Threads and Concurrency 37 | 38 | ### [4. Background Excution](#백그라운드실행) 39 | > 백그라운드 상태로 전환될때 작업 마무리하기, 백그라운드 상태에서 되돌아오기 등 백그라운드 상태와 관련된 내용 40 | 41 | * Executing Finite-Length Tasks 42 | * Downloading Content in the Background 43 | * Implementing Long-Runnig Tasks 44 | * Getting the User's Attention While in the Background 45 | * Understanding When Your App Gets Launched into the Background 46 | * Being a Responsible Background App 47 | * Opting Out of Background Execution 48 | 49 | ### [5. Stragegies for Handling App Stage Transitions](#상태전환) 50 | > 실행, 구동, 백그라운드, 종료, 일시 정지 등과 같은 앱의 실행 상태 변화에 따른 역할과 관련 메소드 사용법에 관한 내용 51 | 52 | * What to Do at Launch Time 53 | * What to Do When Your App Is Interrupted Temporally 54 | * What to Do When Your App Enters the Background 55 | 56 | ### [6. Strategies for Handling App Features](#앱기능) 57 | > 개인정보 활용, 등급제한, 여러 iOS 버전에 대응하기, 앱 상태 보존/복원, VoIP 활용 등 여러가지 앱에서 사용되는 기능에 대한 소개 및 사용법에 관한 내용 58 | 59 | * Privacy Strategies 60 | * Respecting Restrictions 61 | * Supporting Multiple Versions of iOS 62 | * Preserving Your App's Visual Appearance Across Launches 63 | * Tips for Developing a VoIP App 64 | 65 | ### [7. Inter-App Communication](#앱통신) 66 | > iOS에서 이루어지는 앱간의 통신 방법(AirDrop, URLs)에 대한 소개와 데이터 송/수신 방법 67 | 68 | * Supporting AirDrop 69 | * Using URL Schemes to Communicate with Apps 70 | 71 | ### [8. Performance Tips](#성능향상) 72 | > 전력 소모와 메모리 사용 등 앱을 실제로 구동할 때 성능 향상을 위해 고려해야할 여러가지 내용 73 | 74 | * Reduce Your App's Power Consumption 75 | * Use Memory Efficiently 76 | * Tune Your Networking Code 77 | * Improve Your Networking Code 78 | * Improve Your File Management 79 | * Make App Backups More Efficient 80 | * Move Word off the Main Thread 81 | 82 | --- 83 | 84 | 85 | ## [1. Introduction](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007072-CH1-SW1) 86 | >정상적인 앱 구동을 위한 iOS 코어 시스템 및 앱 설계에 관한 문서 87 | 88 | * 본 문서는 iOS 앱을 처음 제작하는 사람들을 위해서가 아니라, 이미 앱을 개발하여 다듬고 향상시키려는 개발자들을 위한 가이드입니다. 89 | * 만약 iOS 개발이 처음이라면 [Start Developing iOS Apps_Swift](https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/index.html#//apple_ref/doc/uid/TP40015214)를 먼저 읽어보세요. 90 | * iOS 기술에 대해 심도있게 알아보려면 [About the iOS Technologies](https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/iPhoneOSTechOverview/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007898)를 참고하세요. 91 | 92 | 93 | ## [2. Expected App Behaviors](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW2) 94 | >Xcode를 이용해 제작된 모든 프로젝트는 즉각 장비에서 구동 될 수 있지만, 그렇다고 App Store에 등록될 준비가 완료된 것은 아닙니다. 모든 앱은 사용자에게 좋은 사용 경험(UX)을 전달하기 위해 어느 정도의 시스템 설정이 필요합니다. 이번 섹션에서는 앱 설계 초기 단계에서 고려해야할 앱의 기본 형태 및 구동에 대해 알아봅니다. 95 | 96 | ### Providing the Requred Resources 97 | >모든 어플은 아래의 리소스 및 메타데이터를 포함해야합니다. 98 | 99 | * 정보 속성 목록 파일(Info.plist) 100 | * 앱 실행 하드웨어 사양 101 | * 한개 이상의 앱 아이콘 102 | * 한개 이상의 앱 런칭 이미지 103 | 104 | #### The App Bundle 105 | >iOS 앱을 생성하게되면 Xcode는 앱을 *bundle*로 묶는데, *bundle*은 앱과 관련된 자원을 그룹화해놓은 파일 시스템의 디렉토리입니다. *bundle*에는 앱 실행 파일, 앱 아이콘, 이미지 파일 및 현지화(localize)된 콘텐츠등의 리소스 파일이 포함되어있습니다. 106 | 107 | * **정보 속성 목록 파일(Info.plist)** : Info.plist 파일은 앱 구성에 관한 중요한 정보가 포함된 구조화된 파일입니다. App Store 및 iOS에서 앱의 기능을 확인하는데 사용되며, 모든 앱이 Info.plist. 파일을 포함해야합니다. 108 | * 기본으로 제공되는 Info.plist 파일에는 필수항목에 대한 기본값이 설정되어있으며, 특정 기능을 위한 항목 추가/변경이 가능합니다. 109 | * Wi-Fi 연결, custom URL 스키마 지원, 사진 앨범 접근등을 위해서는 Info.plist에 적절한 키를 설정해줘야합니다. 110 | * Info.plist의 다양한 키와 값에 대해 자세히 알아보려면 [About Info.plist Keys and Valuse](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009247)를 참고하세요. 111 | 112 | * **앱 아이콘** : 모든 앱은 기기의 홈 화면과 App Store에 표시할 아이콘을 제공해야 합니다. 113 | * 앱 아이콘은 Image Assets에 포함됩니다. 114 | * 아이콘의 크기를 포함하여 아이콘을 디자인 하는 방법에 대한 자세한 내용은 [iOS Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/)을 참고하세요. 115 | 116 | * **런칭 이미지** : 런칭 이미지는 앱을 처음 구동할때 화면에 잠깐 보이는 이미지로, 앱 화면을 구성하고 사용자에게 보여줄 준비가 완료되면 런칭 이미지가 사라집니다. 117 | * 앱이 foregrounde에서 background로 들어갈때는 사용중인 앱의 스냅 샷이 생성되고, 다시 foreground로 되돌아 올대는 런칭 이미지가 아닌 스냅 샷을 활용합니다. 오래도록 앱을 실행하지 않은 경우에는 스냅 샷을 삭제하고 기존의 런칭 이미지를 활용하게 됩니다. 118 | * 런칭 이미지의 크기 및 디자인 방법에 대해서는 [iOS Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/)을 참고하세요. 119 | 120 | --- 121 | 122 | ### Supporting User Privacy 123 | >사용자 개인 정보 보호 및 사용을 위한 앱 설계는 대단히 중요합니다. 대부분의 iOS 장비에는 사용자가 외부에 공개하고 싶지 않은 개인 정보가 포함되어있습니다. 개인 정보를 사용하기 위해서는 반드시 해당 법률에 준수하여 사용자의 동의를 얻은 후에 접근해야합니다. 124 | 125 | * 보호된 데이터 및 리소스의 경우 인증확인 및 요청을 위한 전용 키와 API를 각각 제공합니다. 126 | * 사용자는 접근 권한을 시스템 설정(Setting)에서 언제든지 변경할 수 있으므로, 해당 항목에 접근하기 전에 권한 부여 상태를 확인하십시오. 127 | * 접근시 사용자 권한이 필요한 항목에는 다음과 같은 것이 있습니다. 128 | * 블루투스, 카메라, 달력, 연락처, 건강 정보, 홈킷, 위치정보, 마이크, 기기 모션, 음악, 사진, 미리 알림, 시리, 음성인식, 티비 등 129 | 130 | **\* 중요사항 : 앱에서 보호된 항목에 접근하려고 하면 시스템에서 사용자에게 엑세스 권한을 요청하는 메시지(alert)를 표시합니다. iOS 10 부터는 Info.plist에 각각의 개인 정보를 활용하려는 *목적 문구*를 명시하여 액세스 권한 요청 메시지(alert)에 보이도록 해야합니다.** 131 | 132 | --- 133 | 134 | ### Internationalizing Your App 135 | >iOS 앱은 많은 국가에 배포될 수 있기 때문에 앱 콘텐츠를 지역화하면 더 많은 사용자에게 다가 갈 수 있습니다. 콘텐츠를 현지화하는 과정은 간단한 과정입니다. 136 | 137 | * 지역화 과정을 시작하면 Xcode에서 앱을 현지화 가능한 리소스 파일로 분리하고, 각 리소스를 언어 별 프로젝트(.lproj) 디렉토리를 제공합니다. 138 | * 일반적으로, iOS 앱에서는 다음 유형의 리소스 파일의 현지화가 필요합니다. 139 | * 스토리 보드 파일, 런칭 이미지 파일: 문자열이 포함된 경우 140 | * 오디오 파일: 음성 해설이 포함된 경우 141 | * 언어 별 또는 문화별 컨텐츠가 포함되어 있지 않은 경우 멀티 미디어 파일의 지역화는 하지 않습니다. 142 | 143 | 144 | 145 | ## [3. The App Life Cycle](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW1) 146 | >앱은 작성된 코드와 시스템 프레임 워크간의 정교한 상호작용입니다. 시스템 프레임 워크는 모든 앱의 실행에 필요한 기본 인프라를 제공하며, 개발자는 앱에 어울리는 모양과 느낌을 코드로 구현합니다. 이 둘의 효과적인 상호작용을 위해 iOS 작동원리에 대한 이해가 필요합니다. 147 | 148 | ### The Main Function 149 | > 모든 C 기반의 프로그램과 마찬가지로, iOS 앱의 진입점 역시 main 함수 입니다. iOS에서의 다른 점은 main 함수를 직접 작성하지 않는다는 점입니다. Xcode가 기본 main 함수를 제공해주며, 제공된 main 함수를 수정해서는 안됩니다. 150 | 151 | * main 함수는 UIKit 프레임워크에 제어권한을 넘겨줍니다. UIApplicationMain 함수는 앱의 핵심 객체를 만들고, 스토리 보드 파일로부터 UI를 로드하고, 초기 설정을 위한 코드를 호출하고, 앱의 실행 루프를 동작시킵니다. 152 | * 개발자가 제공해야하는 부분은 스토리 보드파일과 사용자 지정 초기화 코드입니다. 153 | 154 | --- 155 | 156 | ### The Structure of an App 157 | > 앱을 시작하는 동안 UIApplicationMain 함수는 핵심 객체를 설정하고, 앱 실행을 준비합니다. UIApplication 객체는 모든 iOS 앱의 핵심으로, 시스템과 앱 객체 사이의 상호작용을 원활하게 하는 역할을 합니다. 158 | 159 | * iOS 앱은 Model View Controller 아키텍처(MVC 패턴)를 사용합니다. MVC 패턴은 앱의 데이터 부분(혹은 비지니즈 로직)과 이를 어떻게 보여줄지에 대한 부분을 분리합니다. 이러한 패턴은 화면 크기가 다른 다양한 장치에서 앱을 구동하는데 매우 중요한 역할을 합니다. 160 | 161 |
162 | 163 |
164 | 165 | --- 166 | 167 | ### The Main Run Loop 168 | > 앱의 main run loop는 모든 사용자 관련 이벤트를 처리합니다. UIApplication 객체는 실행시 main run loop를 설정하고, 이를 사용해 이벤트를 처리하고 UI 업데이트를 처리합니다. 이름에서 알 수 있듯이, main run loop는 앱의 main thread에서 실행되며, 사용자 이벤트가 입력되면 순차적으로 처리합니다. 169 | 170 |
171 | 172 |
173 | 174 | 175 | * 사용자가 장비와 상호 작용하며 발생된 이벤트는 UIKit에 의해 설정된 특정 포트를 통해 앱에 전달됩니다. 이벤트들은 내부 queue에서 대기하고 있다가 main run loop에 하나씩 전달 됩니다. 176 | * 다양한 유형의 이벤트를 iOS 앱에 전달 할 수 있습니다. 가장 일반적인 이벤트에는 터치, 원격 제어, 모션, 가속도계 및 자이로 스코프 이벤트 등이 있습니가. 각 이벤트에 대한 자세한 내용은 [Event Handling Guid for UIKit Apps](https://developer.apple.com/library/content/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/index.html#//apple_ref/doc/uid/TP40009541)에서 확인 할 수 있습니다. 177 | 178 | --- 179 | 180 | ### Execution States for Apps 181 | > iOS 앱은 언제나 다음 중 하나의 상태값을 지니게됩니다. 182 | 183 | * Not running : 앱이 실행되지 않았거나 혹은 시스템에 의해 종료된 상태 184 | * Inactive : 앱이 foreground에서 실행 중이지만, 일시적으로 이벤트를 받지 못하는 상태 185 | * Active : 앱이 foreground에서 실행 중이며, 사용자 이벤트를 받을 수 있는 상태 186 | * Background : 앱이 백그라운드에서 코드를 실행 중인 상태 187 | * Suspended : 백그라운드에 있는 앱이 더이상 코드를 실행하지 않는 정지된 상태 188 | 189 |
190 | 191 |
192 | 193 | 194 | * iOS 시스템은 전체 시스템에서 발생하는 작업을 처리하며 해당 앱을 여러가지 상태로 이동시킵니다. 예를 들어 사용자가 홈 버튼을 누르거나 전화가 걸려오면 현재 실행 중인 앱이 비활성 상태로 변하게 됩니다. 195 | * 대부분의 상태 전환에는 appDelegate 메소드가 호출 됩니다. 각 메소드를 적절히 사용하면 상태변화에 대응할 수 있습니다. 196 | * `application:willFinishLaunchingWithOptions:` 앱에서 처음으로 코드를 실행 할 수 있습니다. 197 | * `application:didFinishLaunchingWithOptions:` 사용자에게 앱의 화면이 보여지기 전에 마지막으로 초기화를 수행할 수 있습니다. 198 | * `applicationDidBecomeActive:` 앱이 foreground로 전환되는 시점을 알려줍니다. 199 | * `applicationWillResignActive:` 앱이 foreground 상태에서 inactive 되는 시점입니다. 200 | * `applicationDidEnterBackground:` 앱이 background에서 실행되고 있으며, 언제든지 정지될수 있음을 알립니다. 201 | * `applicationWillEnterForeground:` 앱이 background에서 foreground로 진입하고 있지만 아직 active 된 상태는 아닙니다. 202 | * `applicationWillTerminate:` 앱이 종료되고 있음을 알리는 메소드 입니다. 하지만 앱이 시스템에 의해 정지되었을 경우에는 호출 되지 않습니다. 203 | 204 | --- 205 | 206 | ### App Termination 207 | > 앱은 언제든지 종료될 수 있어야 하며, 종료하기 전에 사용자 정보를 저장하거나 특별한 기능을 수행을 위해 기다리지 않습니다. 시스템에 의한 앱 종료는 앱 수명 주기에서 정상적인 부분입니다. 보통은 시스템이 사용하지 않는 메모리를 회수하여 다른 앱을 실행 할 수 있는 공간을 확보하기 위해 종료하지만, 오작동을 하거나 앱이 적절하게 응답하지 않는 경우에도 앱을 종료 시킬 수 있습니다. 208 | 209 | * 시스템에 의해 정지된 앱은 종료 될때 알림을 받지 않지 않고 메모리를 회수당하게 됩니다. 210 | * 사용자가 의도적으로 앱을 종료하는 경우 역시 앱 종료가 앱에 전송되지 않습니다. 211 | 212 | --- 213 | 214 | ### Threads and Concurrency 215 | > 시스템은 기본적으로 앱의 main thread를 생성하는데, 필요에 따라 추가 thread를 생성하여 다른 작업을 수행 할 수 있습니다. iOS 앱의 경우, 직접 thread를 만들고 관리하는 대신 `Grand Central Dispatch(GCD)`, `operation objects`, `asynchronous` 프로그래밍 기법을 사용하는 것이 좋습니다. 216 | 217 | * GCD를 이용하면 수행하고 싶은 작업과, 작업의 순서를 정할 수 있지만, 시스템이 CPU에서 작업을 가장 효과적으로 수행할 수 있는 방법을 결정 할 수 있도록 하는 것이 전반적인 성능을 향상시키고, 코드를 단순화 시킬 수 있습니다. 218 | * Thread와 concurrency(동시성)를 사용할때 다음 사항을 고려하세요. 219 | * View, Core Animation 그리고 UIKit 클래스와 관련된 작업은 main thread에서 실행되어야 합니다. 220 | * 오래 걸리는 작업은 백그라운드 스레드에서 수행해야합니다. 네트워크 작업을 포함하거나, 파일에 접근하거나, 많은 양의 데이터를 처리할 때는 GCD를 이용하여 비동기로 수행해야합니다. 221 | * GCD 및 operation object를 사용한 작업 방법에 대해서는 [Concurrency Programming Guide](https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091)를 참고하세요. 222 | 223 | 224 | ## [4. Background Execution](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1) 225 | > 사용자가 앱을 사용하지 않을 경우 시스템은 앱을 백그라운드 상태로 전환시킵니다. 일반적으로 백그라운드 상태는 정지 상태(suspended)로 가는 길입니다. 앱을 정지 시키는 일을 배터리 수명을 향상 시키는 일이며, 다른 앱이 foreground에서 실행 될수 있는 리소스를 제공해줍니다. 하지만 모든앱이 백그라운드에서 정지되는 것은 아닙니다. 예를 들어 하이킹 앱은 백그라운드에서도 사용자의 위치를 추적해야하며, 오디오 앱은 잠금화면에서도 계속 음악을 재생할 수 있어야 합니다. 이렇게 백그라운드에서 앱을 실행하는 것이 필요하다고 판단되면 iOS는 배터리를 많이 소모하지 않고 효율적으로 수행 할수 있도록 다음과 같은 기술을 제공합니다. 226 | 227 | * foreground에서 짧은 작업을 하는 앱은 백그라운드로 전환될때 해당 작업을 완료할 시간을 요청할 수 있습니다. 228 | * foreground에서 다운로드를 시작하는 앱은 다운로드 관리를 시스템에 전할 할 수 있으므로, 다운로드가 되는 동안 앱이 중지되거나 종료되지 않습니다. 229 | * 특정 유형의 작업을 지원하기 위해 백그라운드에서 실행하는 앱은 하나 이상의 백그라운드 실행 모드에 대한 지원을 선언 할 수 있습니다. 230 | 231 | ### Executing Finite-Length Tasks 232 | > 백그라운드로 이동한 앱이 작업 중인 일을 완료하기 위해 추가적인 시간이 필요한 경우, `UIApplication` 객체의 `beginBackgroundTaskWithName : expirationHandler :` 또는 `beginBackgroundTaskWithExpirationHandler :` 메소드를 호출하여 작업이 완료되기 까지의 추가 시간을 요청 할수 있습니다. 위 메소드 중 하나를 호출하면 앱은 일시적으로 중지가 지연되고, 작업을 마저 실행 할수 있습니다. 작업이 끝난 앱은 `endBackgroundTask:`메소드를 호출하여 시스템에 작업을 마쳤음을 알립니다. 233 | 234 | * `expirationHandler :` 에 종료하기 전에 수행해야하는 코드를 추가 할 수 있지만, 이때 실행되는 작업이 너무 오래 걸리지 않아야합니다. 235 | * 작업을 처리하는데 남은 시간을 알고 싶다면 `UIApplication`의 `backgroundTimeRemaining` 값을 확인하세요. 236 | 237 | --- 238 | 239 | ### Downloading Content in the Background 240 | >파일을 다운로드 할 때는 `NSURLSession` (`URLSession`)객체를 이용해 다운로드를 시작해야 앱이 중지 되거나, 종료 될 경우 시스템에서 다운로드 프로세스를 제어 할 수 있습니다. 백그라운드 다운로드를 지원하는 `NSURLSessionConfiguration` 객체를 통해 작업이 시작되면 적절한 시간에 업로드 또는 다운로드 작업을 시스템에 전달합니다. 241 | 242 | * 앱이 실행중일때 작업이 완료되면 세션 객체는 일반적인 방식으로 `delegate`에 알려줍니다. 243 | * 작업이 끝나지 않은 상태에서 시스템이 앱을 종료하면 시스템은 백그라운드에서 작업을 계속 관리합니다. 244 | * 사용자가 앱을 강제로 종료하면 보류중인 작업이 취소됩니다. 245 | 246 | --- 247 | 248 | ### Implemneting Long-Runnig Tasks 249 | > 구현하는데 많은 시간이 필요한 작업의 경우, 백그라운드에서 실행 될 수있도록 특정 권한을 요청해야합니다. 백그라운드 실행 기능을 위해서는. `Project Setting` - `Capabilities` - `Background Modes` 옵션을 선택해야하며, 이렇게하면 Info.plist 파일에 `UIBackgroundMode` 키가 추가됩니다. iOS에서는 아래와 같은 특정 유형의 기능만 백그라운드에서 실행 할 수 있습니다. 250 | 251 | * 음악 플레이어 앱과 같이 백그라운드에서 사용자에게 미디어 콘텐츠를 재생하는 앱 252 | * 백그라운드에서 오디오 콘텐츠를 녹음하는 앱 253 | * 내비게이션 앱과 같이 항상 사용자에게 위치 정보를 제공하는 앱 254 | * VoIP (Voice over Internet Protocol)를 지원하는 응용 프로그램 255 | * 새로운 콘텐츠를 정기적으로 다운로드하고 처리해야하는 앱 256 | * 외부 액세서리를 정기적으로 업데이트하는 앱 257 | 258 | --- 259 | 260 | ### Getting the User's Attention While in the Background 261 | >알람은 앱이 중지되었거나 백그라운드에 있을때 사용자의 시선을 끌수 있는 방법입니다. 로컬 알림의 사운드, 배지, 알림 기능을 이용하여 사용자에게 알릴 수 있으며 사용자는 앱을 foreground로 되돌려 놓을지 결정해야합니다. 앱이 이미 foreground에서 실행중인 경우, 로컬 알림은 사용자에게 전달되지 않습니다. 262 | 263 | * 로컬 알림을 예약하려면 `UILocalNotification` 클래스의 인스턴스를 만들고 매개변수를 구성한 다음 `UIApplication` 클래스의 메소드를 이용해 일정을 예약 할 수 있습니다. 264 | * 로컬 알림은 알림의 유형(소리, 알림, 배지) 및 알림 시각에 대한 셋팅을 할 수 있습니다. 265 | * `UIApplication` 클래스의 메소드를 사용하여 예약된 알림을 취소하거나 알림 목록을 가져올 수 있습니다. 자세한 내용은 [Local and Remote Notification Programming Guide](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/index.html#//apple_ref/doc/uid/TP40008194)를 참고하세요. 266 | 267 | --- 268 | 269 | ### Understanding When Your App Gets Launched into the Background 270 | >백그라운드 실행을 지원하는 경우, 시스템이 이벤트 처리를 위해 앱을 재실행 시킬 수 있습니다. 사용자에 의해 강제로 앱이 종료되지 않은 이상 다음과 같은 이벤트 중 하나가 발생하면 시스템이 임의로 앱을 재실행하게됩니다. 271 | 272 | * 위치 앱 : 앱에 지정된 특정 지역에 들어왔음을 인지했을때 273 | * 오디오 앱 : 일부 데이터를 처리하기 위해(오디오 재생 혹은 마이크 사용) 274 | * 블루투스 앱 : 연결된 주변 기기에서 데이터를 수신하거나, 중앙으로부터 명령을 받을 때 275 | * 백그라운드 다운로드 앱 : 다운로드를 성공적으로 완료했거나 오류가 발생했을 때 276 | 277 | * 사용자가 강제로 앱을 종료한 경우에는 시스템이 앱을 재실행 하지 않지만, iOS8 이상의 장비에서 위치앱은 재실행됩니다. 278 | * 만일 기기가 비밀번호(지문)으로 보호중이면 사용자가 먼저 기기를 잠금해제 해야 백그라운드 상태에서 앱이 실행됩니다. 279 | 280 | --- 281 | 282 | 283 | ### Being a Responsible Background App 284 | >Foreground 상태의 앱은 시스템 리소스 및 하드웨어 사용과 관련해 항상 백그라운드 상태의 앱보다 우선시 됩니다. 백그라운드에서 실행되는 앱은 이러한 불균등을 대비하여 백그라운드에서 실행될 동작을 준비해야합니다. 특히 백그라운드로 이동하는 앱은 다음 가이드를 준수해야 합니다. 285 | 286 | * **코드에서 OpenGL ES를 호출하지 마십시오.** 백그라운드에서 실행되는 동안 EAGLContext객체를 만들거나 OpenGL ES 드로잉 명령을 실행하면 앱은 즉시 종료됩니다. 백그라운드에서 OpenGL ES를 처리하는 방법에 대해서는 [OpenGL Programming Guide](https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008793)를 참고하세요. 287 | * **앱이 정지 되기 전에 Bonjour 관련 서비스를 취소하십시오.** 앱이 백그라운드로 이동해 정지되기 전에 Bonjour를 취소하고 네트워크 서비스와 관련된 수신 대기 소켓을 닫아야 합니다. 만약 Bounjour 서비스를 직접 취소하지 않으면 시스템이 서비스를 종료시키게됩니다. 288 | * **네트워크 기반 소켓의 연결 오류를 처리 할 수 있도록 준비하십시오.** 시스템은 여러가지 이류로 앱이 정지된 동안 소켓 연결을 해제할 수 있습니다. 신호 손실이나 네트워크 전환 오류에 대비되어있어야 예상치 못한 문제가 발생하지 않습니다. 289 | * **백그라운드로 이동하기 전에 앱 상태를 저장하십시오.** 정지된 앱은 메모리에서 제거되기 전에 앱에 알림이 제공되지 않이 때문에 상태보존 메커니즘을 활용해 앱의 UI 상태를 디스크에 저장해야합니다. 이 기능에 대한 자세한 내용은 [Preserving Your App’s Visual Appearance Across Launches](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforImplementingYourApp/StrategiesforImplementingYourApp.html#//apple_ref/doc/uid/TP40007072-CH5-SW2)을 참고하세요. 290 | * **백그라운드로 이동하기 전에 불필요한 객체에 대한 강한 참조를 해제하세요.** 앱에서 용량이 큰 객체(이미지)를 관리하는 경우, 백그라운드로 이동하기 전에 해당 캐시에 대한 강한 참조를 해제해야합니다. 291 | * **정지되기 전에 공유 시스템 자원 사용을 중지하십시오.** 주소록, 캘린더, 데이터 베이스와 같이 공유 시스템 리소스와 상호작용하는 앱은 정지되기 전에 해당 리소스 사용을 중지해야합니다. 292 | * **View 업데이트를 하지 마십시오.** 앱이 배경에 있을때는 View가 표시되지 않으므로 업데이트를 하지않는 것이 좋습니다. 293 | * **외부 액세서리에 대한 연결 알림 및 연결 해제 알림에 응답하세요.** 294 | * **백그라운드로 이동할 때 활성화된 경고 창을 정리하세요.** 앱을 백그라운드로 전환할때 시스템이 자동으로 `UIActionSheet` 또는 `UIAlertView`를 닫지 않습니다. 백그라운드로 이동하기 전에 적절한 정리를 해야합니다. 295 | * **백그라운드로 이동하기 전에 View에서 민감한 정보를 제거하십시오.** 앱이 백그라운드로 전환되면 시스템은 앱 화면을 스냅 샷으로 찍은 다음, 다시 foreground로 전환 할때 간단히 표시하게 됩니다. `applicationDidEngetBackground:` 메서드에서 돌아오기 전에 비밀 번호나 개인 정보는 숨기도록 해야합니다. 296 | * **백그라운드에 있는 동안 최소한의 작업을 수행하십시오.** 297 | 298 | --- 299 | 300 | ### Opting Out of Backgound Execution 301 | > 백그라운드에서 앱이 전혀 실행하지 않게하려면 Info.plist 파일의 `UIApplicationExitsOnSuspend` 키의 값을 true로 추가하여 백그라운드를 명시적으로 선택해제 할 수 있습니다. 앱이 선택 해제되면 앱 생명 주기가 not-running, inactive, active 상태를 순환하며 백그라운드라 정지 상태로 들어가지 않습니다. 사용자가 홈 버튼을 눌러 앱을 종료하면 `appDelegate`의 `applicationWillTermintae:` 메소드 호출되고 앱이 종료되기 전에 약 5초간 정리되고 not-running 상태로 이동하게됩니다. 302 | 303 | * 백그라운드 실행을 선택해제 하는 것은 권장하지는 않지만, 특정 조건에서는 기본 옵션이 될 수 있습니다. 특히 백그라운드에서 실행되는 코드가 복잡성을 대단히 증가시키는 경우 앱을 종료시키는 것이 간단한 해결책일 수 있습니다. 304 | * 앱이 많은 메모리를 소비하고, 쉽게 메모리를 해제 할 수 없는 경우 시스템이 앱을 빠르게 종료하여 다른 앱을 위한 공간을 확보 할 수 있습니다. 305 | 306 | 307 | ## [5. Strategies for Handling App State Transitions](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html#//apple_ref/doc/uid/TP40007072-CH8-SW1) 308 | > 앱의 실행 상태에 따라 시스템은 어느정도의 기대치를 가지고 있으며, 상태 전환이 발생하면 시스템이 app delegate에게 알림을 줍니다. `UIApplicationDelegate` 프로토콜을 이용해 앱의 상태 변화를 감지하고, 각 상화에 맞는 적절한 대응을 할 수 있습니다. 예를 들어 foreground에서 background로 전환할때 저장되지 않은 데이터를 기록하고, 진행중인 작업을 중지 할 수 있습니다. 이번 세션에서는 상태전환코드를 어떻게 구현하면 좋을지에 대한 팁과 지침을 제공합니다. 309 | 310 | ### What to Do at Launch Time 311 | > 앱이 시작되면(launched) app delegate의 `application:willFinishLaunchingWithOptions:` 와`application:didFinishLaunchingWithOptions:` 메소드를 사용해 다음과 같은 작업을 할 수 있습니다. 312 | 313 | * 앱이 시작된 이유에 대한 정보를 확인하고, 적절하게 대응하십시오. 314 | * 앱의 중요한 데이터 구조를 초기화 하십시오. 315 | * 앱으로 보여줄 Window 및 view를 준비하십시오. 316 | 317 | * 앱이 시작 될때 시스템은 자동으로 `main stroyboard`와 `initial view controller`를 로드합니다. 318 | * `state restoration`(상태복원)을 지원하는 앱의 경우 `willFinishLaunchingWithOptions :` `application : didFinishLaunchingWithOptions :` 두가지 메소드를 이용해 이전 상태 인터페이스로 복원합니다. 319 | * 위 두가지 메소드에서 실행되는 작업은 가능한 가벼워야합니다. 320 | * 앱은 초기화 작업은 5초 이내에 완료되어야 하며, 초기화 작업이 너무 오래 걸리면 시스템이 응답없음으로 간주하고 앱을 종료시킬 수 있습니다. 321 | * 실행 속도를 늦출 수 있는 작업(네트워크 액세스)은 보조 thread에서 실행 되도록 조정해야합니다. 322 | 323 | #### The Launch Cycle 324 | * 앱이 foreground 상태로 들어올때 시스템이 main thread를 생성하고 앱의 main 함수를 호출합니다. 기본 main 함수는 UIKit 프레임워크를 제어하고, 앱이 구동되는데 필요한 초기화 작업을 해줍니다. 325 | * 앱이 background 상태로 시작할때는 foreground 상태로 시작될때와 실행주기에 약간의 차이가 생기는데, 가장 큰 차이점은 작업을 처리한 뒤, 정지(suspend) 될 수 있다는 점입니다. 백그라운 상태로 실행될때에도 시스템은 UI 파일을 로드하지만, 사용자 화면에 표시하지는 않습니다. 326 | * 앱이 어느 상태로 시작되는지 확인하려면 `UIApplication` 객체의 `applicationState` 속성값을 확인해 보면 알 수 있습니다. 327 | 328 | #### Launch in Landscape Mode 329 | * 일반적으로 앱은, 세로 모드로 실행되며 필요한 경우 기기 방향에 맞게 인터페이스를 회전합니다. 만약 가로 방향만 사용하려면 다음과 같은 작업을 수행하여 시스템에 가로 방향으로만 앱이 실행되도록 설정해야합니다. 330 | * Info.plist에 `UIInterfaceOrientation` 키를 추가하고 값을 `UIInterfaceOrientationLandscapeLeft` `UIInterfaceOrientationLandscapeRight` 둘 중 하나로 설정하세요. 331 | * `layout`이나 `autosizing` 옵션이 설정되어있는지 확인하세요. 332 | * `shouldAutorotateToInterfaceOrientation:` 메소드가 `true`를 반환하도록 오버라이드 하세요.(세로모드일 경우 `false`) 333 | 334 | #### Installing App-Specific Data Files at First Launch 335 | * 앱의 구동에 요구되는 데이터나 설정 값 셋팅을 위해 첫 실행 주기(first launch cycle)를 이용할 수 있습니다. 336 | * 앱의 특정 데이터 파일은 Library/Application Support//directory에 위치해야합니다. 337 | * 앱 번들 내에 있는 파일은 code signed 되어있어 수정을 할 수 없기때문에, 만약 수정이 필요한 경우에는 반드시 해당 파일을 샌드박스의 다른 폴더로 복사한 다음 수정해야합니다. 338 | 339 | 340 | --- 341 | 342 | ### What to Do When Your App Is Interrupted Temporaily 343 | > 시스템 알림이 전달되면 앱은 일시적으로 제어권을 잃게되고, 사용자 터치 이벤트를 받아 들이지 않습니다. 이러한 상황을 대비해 앱은 `applicationWillResignActive` 메소드에서 아래와 같은 작업을 수행해야 합니다. 344 | 345 | * 데이터 및 상태를 저장합니다. 346 | * 타이머 및 기타 주기적 작업을 중지합니다. 347 | * 메타데이터 쿼리를 모두 중지합니다. 348 | * 새로운 작업을 시작하지 않도록 합니다. 349 | * 동영상 재생을 중지합니다.(AirPlay를 통한 재생은 제외) 350 | * OpenGL ES 프레임 속도를 재조절합니다. 351 | 352 | * 앱이 일시 정지 상태에서 벗어나 다시 활성 상태로 되돌아 오면 `applicationWillResignActive:` 메소드에서 했던 작업들을 `applicationDidBecomeActive:` 메소드에서 되돌려야합니다. 353 | * 만약 앱에 `NSFileProtectionComplete` 옵션으로 보호된 파일이 있다면, 화면이 잠겨있는동안 해당 파일에 접근하지 못하도록 `applicationWillResignActive:` 메소드에서 해당 파일에 대한 참조를 닫아줘야합니다. 354 | 355 |
356 | 357 |
358 | 359 | 360 | ### What to Do When Your App Enters the Foreground 361 | >Foreground로 들어가면 백그라운드 상태로 이동하면서 중지된 작업을 재개할 수 있습니다. `applicationDidEnterBackground :` 메소드에서 수행 된 작업을 `applicationWillEnterForeground` 메소드에서 실행취소해야하며 `applicationDidBecomeActive:` 메소드는 실행때와 동일한 작업을 계속 수행할 수 있도록 해야합니다. 362 | 363 | * `UIApplicationWillEnterForegroundNotification` 알림을 이용해 앱이 foreground로 다시 들어오는 때를 추측 할 수있습니다. 364 | 365 | #### Be Prepared to Process Queued Notifications 366 | * 정지 상태의 앱이 foreground 또는 background 실행 상태가 될때, 대기 중인(queued) 알람을 처리할 준비가 되어야합니다. 앱이 정지되어 있는 동안에는 앱이 코드를 실행하지 못하므로, 시스템이 관련 알람을 대기열에 추가해두고 코드 실행이 시작되는 순간 앱에 알람을 전달합니다. 367 | * 앱에 전달되는 알람의 내용과 키에는 아래와 같은 것이 있습니다. 368 | * 악세서리 연결 등록 / 연결 해제(`EAAccessoryDidConnectNotification`, `EAAccessoryDidDisconnectNotification`) 369 | * 기기 화면 방향 전환(`UIDeviceOrientationDidChangeNotification`) 370 | * 다량의 시간 변화(`UIApplicationSignificantTimeChangeNotification`) 371 | * 배터리 상태 및 잔량 변화(`UIDeviceBatteryLevelDidChangeNotification`, `UIDeviceVatteryStateDidChangeNotification`) 372 | * 근접 상태 변화(`UIDeviceProximityStateDidChangeNofitication`) 373 | * 보호된 파일의 상태 변화(`UIApplicationProtectedDataWillBecomeUnavailable`, `UIApplicationProtectedDataDidBecomeAvailable`) 374 | * 외부 화면 연결 / 연결 해제(`UIScreenDidConnectNotification`, `UIScreenDidDisconnectNotification`) 375 | * 화면의 스크린 모드 변화(`UIScreenModeDidChangeNotification`) 376 | * Settings에서 변경 가능한 앱 설정값의 변화(`NSUserDefaultsDidChangeNotification`) 377 | * 사용 언어 및 지역 변경(`NSCurrentLocaleDidChangeNotification`) 378 | * 사용자 iCloud 계정 변경(`NSUbiquityIdentityDidChangeNotification`) 379 | 380 | * 대기 중인 알람(queued notification)은 사용자 터치나 입력 전에 앱의 main run loop로 전달됩니다. 381 | * 앱이 재개 될때 눈에 띄는 지체가 발생하지 않도록 이러한 이벤트를 빠르게 처리 할 수 있어야합니다. 382 | 383 | #### Handle iCloud Changes 384 | * iCloud 상태 변화에 따라 앱은 iCloud 관련 UI를 업데이트하거나, 관련문서에 대한 참조 상태를 변경해야합니다. 385 | * 앱에서 iCloud 사용 여부를 묻는 메시지가 이미 표시되는 경우, iCloud 상태가 변경되었다고 해서 다시 메시지를 띄우지 마십시오. 관련된 설정은 앱 환결 설정이나, 시스템 Settings에서 사용자가 지정 할수 있도록 하십시오. 386 | 387 | #### Handle Locale Changes 388 | * 앱이 일시 정지된 상태에서 사용자가 Locale(지역)을 변경하면 날짜, 시간 및 숫자와 같은 정보를 강제 업데이트 할 수 있습니다. 389 | * Locale 변경에 대등하기 위한 코드 국제화와 관련된 자세한 내용은 [Internationalization and Localization Guide](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/Introduction/Introduction.html#//apple_ref/doc/uid/10000171i)를 참고하세요. 390 | 391 | #### Handle Changes to Your App's Settings 392 | * Settings를 통해 관리되는 설정값이 있다면 `NSUserDefaultsDidChangeNotification` 알람을 확인해야 합니다. 앱이 일시 정지되거나, 백그라운드 상태일때 설정을 수정할 수 있으므로 해당 알람을 사용하면 설정 변경에 따른 적정한 반응을 할 수 있습니다. 393 | * 경우에 따라 해당 알림에 응답하는 것은 잠재적인 보안 허점을 줄일 수 있습니다. 암호 또는 기타 보안 관련 정보가 변경된 경우 인터페이스를 적절히 업데이트 해야합니다. 394 | 395 | --- 396 | 397 | ### What To Do When Your App Enters the Bakcground 398 | > Foreground에서 백그라운드로 이동할때는 `applicationDidEnterBackground:` 메소드를 사용하여 다음과 같은 작업을 수행할 수 있습니다. 399 | 400 | * 앱 스냅샷 준비 401 | * 메모리 확보 402 | 403 | * `applicationDidEnterBackground:` 메소드는 약 5초 동안 모든 작업을 수행하게 되는데, 작업 수행 이내에 메소드가 return 되지 않으면 앱에 종료되고 메모리에서 제거됩니다. 404 | * 작업 수행에 더 많은 시간이 필요한 경우 `beginBackorundTaskWithExpirationHandler:` 메소드를 호출하여 백그라운드 실행 시간을 요청한 다음, 보조 스레드에서 장시간 작업을 수행합니다. 405 | * 백그라운드 작업을 시작하는지 여부에 관계없이 `applicationDidEnterBackground:` 메소드는 5초 이내에 종료되어야 합니다. 406 | 407 | #### The Background Transition Cycle 408 | * 사용자가 홈 버튼을 누르거나, Sleep/Wake 버튼을 눌렀을 때, 시스템에 다른 앱을 실행 시킬때 foreground에 있던 앱을 비활성 상태(inactive state)가 되었다가 백그라운드 상태로 진입하게 됩니다. 이러한 상태 변화는 `applicationWillResignActive:` 와 `applicationDidEnterBackground:` 메서드를 호출하게 됩니다. 409 | * 대부분의 앱은 `applicationDidEnterBackground:` 메소드가 호출 되고, 잠시후 일시 중지 상태로 전환됩니다. 410 | 411 |
412 | 413 |
414 | 415 | #### Prepare for the App Snapshot 416 | * app delegate의 `applicationDidEnterBackground:` 메소드가 반환 되고 잠시 후 시스템은 앱의 화면을 스냅샷을 촬영합니다. 417 | * 백그라운드 작업 수행이 진행되어 화면에 변화가 생기면, 시스템은 스냅샷에 변화 사항을 반영합니다. 418 | * 촬영된 스냅샷은 멀티 태스킹 UI에 사용됩니다. 419 | * 백그라운드에 진입할때 view에 변화를 주는 경우, `snapshotViewAfterScreenUpdates:` 메소드를 호출하여 변경 사항을 렌더링 할 수 있습니다. 420 | * `snapshotViewAfterScreenUpdates:` 메소드의 매개변수를 `true` 값으로 설정하면 강제로 스냅샷을 업데이트 합니다. 421 | 422 | #### Reduce Your Memory Footprint 423 | * 시스템은 최대한 많은 메모리를 유지하려고 시도하며, 메모리가 부족한 경우에는 일시 중지된 앱을 종료하여 메모리를 회수합니다. 424 | * 백그라운드에서 대용량의 메모리를 사용하는 경우, 종료 1순위 대상이 됩니다. 425 | * 백그라운드에 들어갈때, 앱은 더 이상 필요없는 개체에 대한 강한 참조를 해제해야합니다. 426 | * 가능한 빨리 강한 참조를 해제해야 하는 객체에는 아래와 같은 예가 있습니다. 427 | * 생성한 이미지 객체 428 | * 디스크에서 다시 로드할 수 있는 대형 미디어 또는 데이터 파일 429 | * 앱에 당장 필요하지 않으며, 나중에 쉽게 다시 만들 수 있는 모든 객체 430 | 431 | 432 | ## [6. Strategies for Implementing Specific App Features](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforImplementingYourApp/StrategiesforImplementingYourApp.html#//apple_ref/doc/uid/TP40007072-CH5-SW1) 433 | >각각의 앱은 서로 다른 기능과 필요성을 지니지만, 일부 특징은 다양한 앱에는 공통적입니다. 이번 섹션에서는 특정 유형의 기능을 어떻게 앱에서 구현할 수 있는지에 대한 가이드라인을 제시합니다. 434 | 435 | ### Privacy Strategies 436 | > 사용자의 개인 정보를 보호하는 것은 앱을 디자인할때 고려해야할 주요사항 입니다. 보호되어야 할 개인정보에는 사용자의 신원 및 개인 정보와 사용자의 데이터가 포함됩니다. 시스템 프레임워크는 연락처와 같은 데이터를 관리하기 위해 개인 정보 제어를 기본적으로 제공하지만, 앱은 로컬에서 사용하는 데이터를 보호하기위해 개별 적인 조치를 취해야 합니다. 437 | 438 | #### Protecting Data Using On-Disk Encryption 439 | > 데이터 보호는 내장된 하드웨어에 암호화 된 형식으로 파일을 저장하고, 필요할때 암호를 해독하는 방식을 사용합니다. 사용자긔 기기가 잠겨있는 동안에는 해당 파일을 만든 앱도 파일에 접근 할 수 없습니다. 데이터 보호는 대부분의 iOS 기기에서 사용할 수 있습니다. 440 | 441 | * 파일을 보호하려면 원하는 보호 수준을 나타내는 속성을 파일에 추가하십시오. 442 | * `NSData` 클래스 또는 `NSFileManager`클래스를 사용하여 보호 여부를 지정할 수 있습니다. 443 | * `NSData`의 `writeToFile: options: error:` 메소드를 사용하여 새로 작성하는 파일에 보호 설정을 할수 있습니다. 444 | * `NSFileManager` 의 `setAttributes: ofItemAtPath: error:` 메소드를 사용해 기존 파일의 보호 값을 설정 할 수 있습니다. 445 | * 모든 개체는 `UIApplication`의 `protectedDataAvailable` 속성 값을 검사하여 현재 파일에 접근이 가능한지 여부를 확인 할수 있습니다. 446 | * 새롭게 작성하는 파일의 경우, 데이터를 작성하기 전에 보호하는 것이 좋습니다. 447 | 448 | #### Identifying Unique Users of Your App 449 | > 앱에서 사용자를 식별하는 작업을 수행 할때는 항상 투명하게 작업해야합니다. 사용자를 식별하는데 사용되는 몇가지 방법에는 다음과 같은 방법이 있습니다. 450 | 451 | * 사용자 정보로 로그인하는 화면을 구현해 서버의 특정 계정에 연결합니다. 452 | * `UIDevice`의 `identifierForVendor` 속성을 이용해 서로다른 장치 사용자를 구분합니다. 453 | * 광고 목적으로 사용자를 식별하기 위해서는 `ASIdentifierManager` 클래서의 `advertisingIdentifier` 값을 이용해 사용자 ID를 확보 할 수 있습니다. 454 | 455 | --- 456 | 457 | ### Respecting Restrictions 458 | > 사용자는 앱에 사용되는 미디어의 등급을 지정하여 제한 설정할 수 있습니다. 만약 앱이 미디어를 포함하거나 수정하는 경우, 제한 설정을 확인하고 그 변경사항에 맞는 응답을 해야합니다. 459 | 460 | * 제한 설정 값을 가져오려면 `standardUserDefaults` 객체의 `objectForKey`메서드를 사용해 각 값을 확인 할 수 있습니다. 461 | * `com.apple.content-rating.ExplicitBooksAllowed` 462 | * `com.apple.content-rating.ExplicitMusicPodcastsAllowed` 463 | * `com.apple.content-rating.AppRating` 464 | * `com.apple.content-rating.MovieRating` 465 | * `com.apple.content-rating.TVShowRating` 466 | * `objectForKey`가 위 특정 키에 대해 `nil`을 반환하면 해당 정보를 사용할 수 없음을 의미합니다. 이런 경우에는 앱 자체 정책을 사용하여 적절한 등급을 결정 할 수 있습니다. 467 | 468 | --- 469 | 470 | ### Supporting Multiple Versions of iOS 471 | > 최신버전의 iOS와 이전 버전을 함께 지원하는 앱의 경우, 이전 버전의 iOS에서 최신 API를 사용하지 못하도록 런타임 검사를 실시해야합니다. 런타임 검사는 현재 OS에서 사용할 수 없는 기능을 사용하려고 할때 발생하는 앱 충돌(crash)를 방지해줍니다. 472 | 473 | * 해당 class가 존재하는지 검사하기 위해 Class 객체가 nil인지 아닌지 확인하는 방법이 있습니다. 474 | * 해당 메소드를 사용할 수 있는지 확인하기 위해 `instancesRespondToSelector:` 또는 `respondsToSelector:`를 사용할 수 있습니다. 475 | * 여러가지 대상을 지원하는 코드를 작성하는 방법에 대해서는 [SDK Compatibility Guide](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Introduction/Introduction.html#//apple_ref/doc/uid/10000163i)를 참고하세요. 476 | 477 | --- 478 | 479 | ### Preserving Your App's Visual Appearance Across Launches 480 | > 백그라운드로 전환된 앱은 현재 foreground에서 구동되는 앱의 메모리 확보를 위해 언제든지 시스템에 의해 종료 될수 있습니다. 하지만 사용자는 앱을 전환하거나 할때 앱이 일시 종료되었다고 생각하고, 완전히 종료되었다고 생각하지 않기 때문에 마지막 사용시점으로 되돌아오는 것이 좋습니다. 이러한 동작은 사용자에게 더 나은 UX를 제공할 수 있습니다. 이번 세션에서는 iOS의 infrastrucure를 활용해 상태 보존/복원(state preservation, restroration)을 구현 하는 방법을 알아봅니다. 481 | 482 | * `UIKit`의 상태 보존 시스탬은 `View Controller`와 `View`의 상태를 보존, 복원하기 위한 간단하고 유연한 infrastructure을 제공합니다. 483 | * Infrastructure는 적절한 시점에 보존 및 복구 프로세스를 추진합니다. 484 | * 앱의 상태 보존을 위해 고려해야하는 위치는 다음 세가지가 있습니다. 485 | * App delegate 객체 (앱의 최상위 레벨 상태 관리) 486 | * View Controller 객체 (앱의 전반적인 UI 관리) 487 | * Custom Views (보존해야할 custom data가 있는 경우) 488 | 489 | #### Enablikng State Preservation and Restoration in Your App 490 | * 앱의 상태 보존/복원은 자동기능이 아니므로, 앱에서 사용하도록 선택해야합니다. 491 | * App delegate에서 다음 메소드를 구현하여 `true`값이 반환되도록 합니다. 492 | * `application: shouldSaveApplicationState:` 493 | * `application: shouldRestoreApplicationState:` 494 | 495 | #### The Preservation and Restoration Process 496 | > 앱 상태 보존 / 복원 기능을 이용하기 위해서는 앱에서 보존되어야할 객체를 식별해줘야 `UIKit`에서 적절한 시점에 객체를 보존 / 복원하는 작업을 수행 할 수 있습니다. `UIKit` 은 보존 / 복원 프로세스의 많은 부분을 처리하므로, 어떻게 작업을 하는지 알아두면 전반적인 코드 작성과 흐름이해에 용이합니다. 497 | 498 | * 상태 보존 / 복원을 고려할때, 두가지 프로세스를 분리하는 것이 좋습니다. 499 | * 보존: 앱이 foreground와 background를 오고갈때 `UIKit`은 앱의 상태를 적절히 보존합니다. 상태 보존에 필요한 관련 데이터를 암호화된 디스크 상의 파일에 쓰고, 다음번에 앱이 launch될때 `UIKit`이 해당 파일을 찾아 앱 상태 복원 시도합니다. 물론, 이때 파일은 암호화 되어있기 때문에 기기가 잠금해제 되어있는 경우에만 발생합니다. 500 | * 복원: 상태를 복원하는 동안 `UIKit`은 보존 된 데이터를 사용하여 UI를 재구성 하지만, 실제 객체 생성은 코드에 의해 처리됩니다. Storyboard에 접근해 객체를 로드하는 것은 가능하지만, 실제로 어느 객체가 필요한지, 어느 객체가 생성되었는지는 코드를 통해서 알 수 있기 때문입니다. 객체가 생성되면 `UIKit`이 보존해 놓은 자료를 이용해 객체를 초기화 합니다. 501 | * 각각의 상태에서 앱은 다음과 같은 역할을 하게됩니다. 502 | * 보존 503 | * `UIKit`에 상태 보존을 해야한다고 알립니다. 504 | * `UIKit`에 어떤 `ViewController`와 `View`가 보존 될지 알립니다. 505 | * 보존되는 객체에 대한 데이터를 인코딩해야합니다. 506 | * 복원 507 | * `UIKit`에 상태 복원을 해야한다고 알립니다. 508 | * `UIKit`에서 요청한 객체를 제공(생성) 해야 합니다. 509 | * 복원할 객체의 상태를 디코딩하고, 이를 이용해 객체를 이전 상태로 되돌립니다. 510 | * 가장 중요한 부분은 `UIKit`에게 보존 / 복원할 객체를 알려주는 것으로, 관련 코드를 디자인 할때 대부분의 시간을 소비해야합니다. 511 | * 몇몇 `ViewContrller`는 앱의 `main storyboard`에서 자동으로 로드되지만 `push`되거나 `present`되는 `ViewController`들은 접근이 불가능 하기 때문에 `restoreation idientifier`를 지정해줘야합니다. 512 | 513 |
514 | 515 |
516 | 517 | * 보존하려는 `view controller`에 대해 추후 어떤 방식으로 복원될지 결정해야합니다. `UIKit`는 두가지 방식을 제공합니다. App delegate를 이용해 재구성하거나 view controller에 `restoration class` 를 구현하는 방식이 있습니다. 각 방식에 대한 사용팁은 아래와 같습니다. 518 | * 만약 main storyboard를 통해 view controller가 항상 로드된다면, `restore class` 를 구현하지 마십시오. 대신 app delegate를 이용해 객체를 복원하십시오. 519 | * 만약 main storyboard를 통해 view controller가 로드되지 않는다면, `restore class`를 구현하는 것이 좋습니다. 520 | 521 | #### What Happnes When You Exclude Groups of View Controllers? 522 | > 어떤 view controller의 restore identifier가 `nil`이면 해당 view controller와 이의 child view controllers은 보존 데이터에서 제외됩니다. 만일 child view controller를 수동으로 보존하려면 childe view controller에 개별적으로 rester identifier를 지정해주면됩니다. 523 | 524 | #### Checklist for Implementing State Presevtion and Restoration 525 | > 앱의 상태 보존 / 복원을 지원하려면 app delegate와 view controller가 상태 정보를 인코딩/ 디코딩 할 수 있도록 수정해야합니다. 상태 보존 / 복원 기능 추가를 위한 코드 작성시, 아래 체크리스트를 확인하십시오. 526 | 527 | * (필수) `application:shouldSaveApplicationState:`, `application:shouldRestoreApplicationState:`를 구현하십시오. 528 | * (필수) 보존하려는 각각의 view controller의 `restorationIdentifier`에 빈값이 아닌 String값 입력하십시오. 529 | * (필수) `application:willFinishLaunchingWithOptions:` 에서 복원할 스크롤 위치와 관련 UI 설정을 위해 window를 살피십시오. 530 | * 필요하다면 view controller에 `restoration class`를 구현하십시오. 531 | * 보존 / 복원 하려는 view controller 혹은 view에 `encodeRestorableStateWithCoder:`와 `decodeRestorableStateWithCoder:`메소드를 추가하십시오. 532 | * 테이블 뷰나 콜렉션 뷰에서 data soucre역할을 하는 객체는 `UIDataSourceModelAssociation protocol`을 구현해야합니다. 필수사항은 아니지만 이 프로토콜은 해당 뷰에서 선택되거나 보이는 영역의 복원을 도와줍니다. 533 | 534 | #### Enabling State Preservation and Restoration in Your App 535 | > 앱 상태 보존 / 복원을 자동 기능이 아니므로 app delegate에서 아래 두 메소드를 구현해 기능 지원을 명시해야합니다. 536 | 537 | * `application:shouldSaveApplicationState:` 538 | * `application:shouldRestoreApplicationState:` 539 | 540 | #### Preserving the State of Your View Controllers 541 | > View controller의 상태 보존을 위해서는 다음 작업을 해야합니다. 542 | 543 | * (필수) `restore identifier` 할당 544 | * (필수) 앱 실행 시점(launch)에서 새로운 view controller 를 생성할 코드 작성 545 | * (옵션) 앱을 다시 실행했을때 재생성 되지 않는 상태 정보를 위해 `encodeRestorableStateWithCoder:`와 `decodeRestorableStateWithCoder:` 메소드 구현 546 | 547 | #### Preserving the State of Your Views 548 | > 특정 view에 보존할만한 가치가 있는 정보가 있다면, view가 포함된 view controller의 나머지 부분과 함께 보존 될 수 있습니다. view의 상태를 저장하는 경우는 view 자신이 속한 view controller와 독립적으로 사용자가 변경할 수 있는 경우입니다. 예를들어 스크롤뷰는 스크롤의 현재 위치값(position)을 저장하게되는데 이는 view controller는 관심이 없는 값입니다. 뷰의 상태값을 저장하기 위해서는 다음과 같은 작업을 해야합니다. 549 | 550 | * view의 `restoretionIdentifier`값을 할당합니다. 551 | * view가 속해있는 view controller도 유효한 `restorationIdentifier`값을 지녀야합니다. 552 | * tableView와 collectionView의 경우 `UIDataSourceModelAssociation protocol`을 준수하십시오. 553 | 554 | #### Preserving Your App's High-Level State 555 | > view controller와 view에 보존 되는 데이터가 아니라도, 다음 두 메소드를 이용해 앱에 필요한 기타 데이터를 저장 할 수 있습니다. 556 | 557 | * `application:willEncodeRestorableStateWithCoder:` 558 | * `application:didDecodeRestorableStateWithCoder:` 559 | 560 | > 위 메소드는 보존 프로세스의 맨 처음에 호출 되므로 UI의 현재 버전 등과 같은 high-level의 앱 상태를 저장 할 수 있습니다. 561 | 562 | #### Tips for Saving and Restore State Information 563 | > 앱 상태 보존 / 복원을 구현하는 경우 다음 지침을 고려하십시오. 564 | 565 | * **버전 정보를 앱 상태와 함께 인코딩 합니다.** 보존을 할때에는 앱의 현재 UI 버전을 식별할 수 있는 버전 문자열 또는 숫자를 인코딩 하는 것이 좋습니다. 버전 정보는 app delegate의 `application:willEncodeRestorableStateWithCoder:` 메소드에서 인코딩 할수 있으며, `application:shouldRestoreApplicationState:` 메소드가 호출 될때 인코딩 되었던 정보를 확인할 수 있습니다. 566 | * **앱 상태 정보에 데이터 모델 객체를 포함하지 마십시오.** 앱은 iCloud 또는 디스크의 로컬 파일에 데이터를 별도로 저장해야합니다. 상태 복원 메커니즘을 사용하여 데이터 저장시, 복원 작업중에 문제가 발생하면 보존 된 데이터가 삭제 될 수 있습니다. 567 | * **앱 상태 보존은 기존에 디자인된 방식으로 view controller를 사용할 것을 기대합니다.** 앱의 view controller 계층 구조는 기존에 설계된 방식을 유지해야합니다. view controller간의 계층/포함 관계와 상과없이 view를 보여주는 경우 보존 시스템이 보존할 view controller를 제대로 찾아내지 못할 수도 있습니다. 568 | * **모든 view controller를 보존하는 것은 의도에 맞지 않을 수있습니다.** 어떤 경우의 view controller는 보존하는 것이 적절하지 않을 수 있습니다. 예를 들어 사용자의 민감한 정보가 있는 화면은 보존 / 복원하지 않습니다. 569 | * **복원 프로세스 중에 view controller 클래스를 변경하지 마십시오.** 복원 하는 동안 앱의 클래스가 보존했던 객체의 클래스와 일치 하지 않거나 하위 클래스가 아니면 복원 작업을 하지 않습니다. 570 | * **사용자가 강제로 앱을 종료하면 시스템에서 앱의 보존 상태를 자동으로 삭제합니다.** 앱이 종료될때 복원 상태를 삭제하는 것은 일종의 안정 장치입니다. 보존 / 복원 기능을 테스트 하려면 멀티태스킹 상태를 사용하지 말고 Xcode를 이용해 임시 명령이나 제스처로 exit를 호출하도록 하십시오. 571 | 572 | --- 573 | 574 | ### Tips for Developing a VoIP App 575 | > VoIP(Voice over Internet Protocol) 앱을 통해 사용자는 기기의 셀룰러 서비스 대신 인터넷 연결을 이용해 전화를 걸 수 있습니다. iOS 8 이상에서는 APN(Apple Push Notification Serviece) 및 PushKit 프레임 워크의 API를 사용하여 VoIP 앱을 만들 수 있습니다. 푸쉬기능을 기용하면 VoIP 사용을 위한 지속적인 네트워크 연결이나 소켓 구성을 하지 않아도 됩니다. VoIP 푸시가 도착하면 앱이 푸시를 처리할 시간이 주어집니다(앱이 종료된 상태에도). 576 | 577 | * VoIP 구현을 위해 다음과 같은 요구사항들이 있습니다. 578 | * **앱에 VoIP 백그라운드 모드를 사용해야합니다.** Xcode project Capabilities 탭에서 백그라운드 모드를 활성화 합니다. 보통 VoIP 앱은 오디오 내용을 포함하기 때문에 Audio 및 AirPlay 백그라운드 모드도 사용하는것이 좋습니다. 579 | * PushKit API를 사용하여 VoIP 푸시 알림을 수신하고, 수신 알람을 처리하도록 하십시오. 580 | * 오디오 세션을 구성하고 활성화 시키십시오. 581 | * iPhone에서 더 나은 UX를 보장하려면 `Core Telephony` 프레임 워크를 이용하십시오. 582 | * VoIP 백그라운드 모드를 활성화 하면 백그라운드에서 오디오를 재생할 수도 있고, 시스템 부팅 직후 백그라운드에서 재시작 되어 VoIP 서비스를 항상 사용 할수 있습니다. 583 | 584 | 585 | #### Using the Reachability Interfaces to Improve the User Experience 586 | > VoIP 앱은 네크워크 환경에 크게 의존하기 때문에, `System Configuration framework`의 `reachability interface`를 활용해 네크워크 가능성을 확인하고 결과에 맞게 동작을 조정해야합니다. `reachability interface`를 사용하면 네트워크 상태가 변경 될때마다 앱에 알림을 보낼 수 있습니다. 변경 사항을 감지하여 사용자에게 VoIP 연결 상태에 대해 알려주도록 해야합니다. 587 | 588 | * 네트워크 가용성을 파악해 앱의 동작을 조정하면, 기기의 배터리 수명을 향상 시킬 수 있으며 앱이 더 자주 잠자기 상태로 있을 수 있습니다. 589 | * `reachability interface`에 대한 자세한 내용은 [System Configuration Framework Reference](https://developer.apple.com/reference/systemconfiguration)를 참고하세요. 590 | 591 | 592 | ## [7. Inter-App Communication](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW2) 593 | > 기기내 앱간 통신은 간접적인 방식을 통해서만 가능합니다. AirDrop을 사용하여 다른 앱과 파일 및 데이터를 공유 할 수 있습니다. 또한 앱 URL을 사용하여 앱에 정보를 보낼 수 있도록 custom URL Schemes을 정의할 수 있습니다. 594 | > * 참고: `UIDocumentInteractionController` 객체 또는 `document picker`를 사용하여 앱간 파일 교환도 가능합니다. `UIDocumentInteractionController`에 대한 정보는 [Document Ineraction Programming Topics for iOS](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010403)를, `document picker`에 관한 정보는 [Document Picker Programming Guide](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40014451)를 참고하세요. 595 | 596 | ### Supporting AirDrop 597 | > AirDrop을 통해 근처에 있는 기기와 사진, 문서, URL 그리고 각종 데이터들을 공유 할 수 있습니다. AirDrop은 peer-to-peer 네트워킹을 통해 주변 기기를 찾고 연결합니다. 598 | 599 | #### Sending Files and Data to Another App 600 | > AirDrop을 이용해 파일과 데이터를 전송하려면 `UIActivityViewController` 객체를 사용하십시오. `UIActivityViewController`객체를 사용하면 현재 보여지는 UI 화면에 activity sheet를 보여줍니다. 해당 객체를 생성할때 전송하려는 데이터를 지정하십시오. `UIActivityViewController`는 특정 데이터를 지원 가능한 activities만 표시해줍니다. AirDrop의 경우 이미지, 문구, URL 그리고 몇몇 다른 타입의 데이터 전송이 가능합니다. `UIActivityItemSource` 프로토코를 채택한 custom 객체 전송도 가능합니다. 601 | 602 | * 더 많은 정보를 보려면 [UIActivityViewController Class Reference](https://developer.apple.com/reference/uikit/uiactivityviewcontroller)와 [UIActivity Class Reference](https://developer.apple.com/reference/uikit/uiactivity)를 참고하세요. 603 | 604 | #### Receiving Files and Data Send to Your App 605 | > AriDrop을 통해 수신한 파일을 받으려면 아래와 같은 작업을 하십시오. 606 | 607 | * Xcode에서 앱에서 열 수 있는 문서 타입을 명시하십시오. 608 | * app delegate에 ` application:openURL:sourceApplication:annotation:` 메소드를 구현하여 다른 앱을 통해 받은 데이터를 받으십시오. 609 | 610 | * Xcode project Info 탭에 앱에서 지원가능한 문서 타입을 지정할 수 있는 문서 유형 섹션이 있습니다. 문서 유형의 이름과 데이터 유형을 나타내는 하나 이상의 UTI를 지정해야합니다. 예를 들어 png 파일에 대한 지원을 선언하려면 public.png를 UTI 문자열로 포함합닏. iOS는 지정된 UTI를 사용하여 앱이 주어진 문서를 열 수 있는지 확인합니다. 611 | * 문서를 앱 컨테이너에 전송 받게 되면 (필요한 경우)시스템이 앱을 launch 하고 app delegate의 `application:openURL:sourceApplication:annotation:` 메소드를 호출하게 됩니다. 이때 앱이 foreground 상태라면 이 메소드를 사용해 유저에게 파일을 보여주고, background 상태라면 나중에 열 수 있는 파일이 있음을 노트해둬야합니다. 612 | * AirDrop을 통해 전송 된 파일은 암호화 되기 때문에 장치가 잠금 해제 되어있지 않으면 파일을 열 수 없습니다. 613 | * AirDrop을 이용해 전송받은 파일은 앱에서 읽고, 삭제하는 것은 가능하지만 편집은 불가능 합니다. 614 | 615 | --- 616 | 617 | ### Using URL Schemes to Communicate with Apps 618 | > URL scheme을 사용하면 정의해둔 프로토콜을 통해 다른 앱과 통신 할 수 있습니다. Scheme을 구축해둔 앱과 통신 하려면 적절한 형식의 URL를 구성하고 시스템에 열어달라고 요청해야합니다. 특정 sheme을 사용하려면 해당 scheme에 대한 지원여부를 선언하고, 해당 sheme을 통해 들어오는 URLs을 처리해야합니다. 619 | 620 | * Apple은 http, mailto, tel 그리고 sms URL scheme에 대한 내장 지원을 제공합니다. 또한 Maps, YouTube 그리고 iPod 앱을 대상으로 하는 http기반 URL도 지원합니다. 621 | * 기본 scheme에 대한 핸들러는 고정되어있으며 변경 할 수 없습니다. (Apple에서 지원하는 것과 동일한 scheme을 사용하면 시스템에서는 기본 앱을 실행합니다.) 622 | * Apple에서 지원하는 기본 scheme을 확인하려면 [Apple URL Scheme Reference](https://developer.apple.com/library/content/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007899)를 참고하세요. 623 | 624 | #### Sending a URL to Another App 625 | > 앱에 구현해 놓은 custom URL scheme을 이용해 데이터를 보내려면 적절한 URL을 먼저 생성하고 `openURL:` 메소드를 호출 하면 됩니다. 626 | 627 | #### Implementing Custom URL Schemes 628 | > 앱에서 특별한 형태의 URL을 수신 하려면, 해당 URL scheme를 시스템에 등록해야합니다. 앱은 종종 custom URL scheme를 이용해 다른 앱에서 서비스를 이용 할수 있도록 합니다. 예를 들어 지도 앱은 특정 위치를 지도에 표시하기 위한 URL을 지원합니다. 629 | 630 | * Registering Custom URL Schems: 앱에 custom URL을 등록하려면 Info.plist 파일에 `CFBundleURLTypes` 키를 포함하십시오. `CFBundleURLTypes` 키에는 dictionary가 array로 들어가 있습니다. dictionary는 `CFBundleURLName`, `CFBunldeURLSchemes` 키로 이루어져 있습니다. 631 | 632 | * Handling URL Requests: custom URL scheme를 갖는 앱은 전달되는 URLs을 잘 처리 할 수 있어야 합니다. 모든 URLs은 app delegate를 통해 전달 됩니다. 전달된 URLs을 핸들하기 위해 아래 메소드들을 구현해야합니다. 633 | * `application:willFinishLaunchingWithOptions:`, `application:didFinishLaunchingWithOptions:` : 전달 받은 URL에 대한 정보를 파악하고, URL을 오픈할지 결정합니다. 둘 중 하나의 앱이 `false`를 반환하면 핸들링 코드는 호출되지 않습니다. 634 | * `application:openURL:sourceApplication:annotation:` : 전달받은 파일을 열기 위한 메소드입니다. 635 | 636 | #### Displaying a Custom Launch Image When a URL is Opened 637 | > Custom URL schemes을 지원하는 앱은 각 scheme에 custom launch image를 제공 할 수 있습니다. URL을 처리하기 위해 앱을 실행하고 관련 스냅 샷을 사용 할 수 없는 경우 제공한 launch image가 표시됩니다. launch image를 지정하려면 다음 규칙을 사용하는 이름의 png 이미지를 제공하십시오. 638 | 639 | \-\\.png 640 | 641 | * **basename**: Info.plist 파일에 있는 UILaunchImageFile키로 지정된 기본 이미지 이름을 나타냅니다. 642 | * **url_scheme**: URL sheme의 이름입니다. 643 | * **other_modifiers**: 이미지에 덧붙일수 있는 수식어는 [Information Property Key Reference](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009247)를 참고하십시오. 644 | 645 | 646 | ## [8. Performance Tips](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/PerformanceTips/PerformanceTips.html#//apple_ref/doc/uid/TP40007072-CH7-SW1) 647 | > 앱 설계(design)가 전반적인 성능에 미치는 영향에 대해 개발 각 단계 마다 고려해야합니다. 전력 사용량과 메모리 사용량은 iOS 앱에 매우 중요한 고려 사항이며, 이 외에도 고려할 사항이 많이 있습니다. 이번 세션에서는 개발 프로세스 전반에서 앱 성능을 위해 고려해야할 요소에 대해 설명합니다. 648 | 649 | ### Reduce Your App's Power Cunsumption 650 | > 모바일 기기에서 전력 소모는 항상 이슈입니다. iOS의 전원 관리 시스템은 현재 사용되지 않는 하드웨어 기능을 종료하여 전력을 절약합니다. 아래의 기능 사용을 최적화 하여 배터리 수명을 향상 시킬 수 있습니다. 651 | 652 | CPU, Wi-Fi, 블루투스, 셀룰러 데이터(4G, 3G), 라디오, 위치 시스템, 가속도계, 디스크 653 | 654 | * 앱 최적화의 목표는 최대한 효율적으로 가능한 많은 작업을 수행하는 것입니다. Instruments를 사용하여 앱의 알고리즘을 항상 최적화 해야합니다. 그러나 가장 최적화 된 알고리즘 조차도 기기 배터리에 부정적인 영향을 미칠 수 있으므로 코드를 작성할때 다음 지침을 고려하십시오. 655 | * Polling이 필요한 작업을 하지 마십시오. Polling 작업은 CPU가 잠자기 모드가 되는 것을 방지 합니다. Polling 대신 NSRunLoop 또는 NSTimer 클래스를 사용하여 필요에 따라 작업을 예약하십시오. 656 | * 가능하면 `UIApplication`의 `shared` 객체의 `idleTimerDisabled` 속성을 `false`로 설정하십시오. IdleTimer는 일정 시간 동안 사용되지 않는 기기의 화면을 끄는 기능을 하는데, 앱 화면을 계속 켜둘 필요가 없는 경우 시스템이 종료시킬 수 있도록 하십시오. 657 | * 가능한 작업을 병합하는 것이 좋습니다. 오랜 시간 동안 작은 chunk로 작업을 수행하는 것 보다 한번에 작업을 수행하는 것이 더 적은 전력을 소비하기 때문입니다. 658 | * 디스크에 너무자주 access하지 마십시오. 예를 들어 앱이 상태 정보를 디스크에 저장하는 경우, 상태에 변경이 생길때만 정보를 저장하고 가능하면 변경 사항을 통합하여 너무 빈번하게 변경 사항을 기록하지 않도록 합니다. 659 | * 필요이상으로 빠르게 화면을 그리지 마십시오. 그리기(draw) 작업은 전력이 많이 소모되는 작업입니다. 660 | * `UIAccelerometer` 클래스를 사용하여 가속도계 이벤트를 수신하는 경우, 필요하지 않을때는 이벤트 전달을 비활성화 하십시오. 자세한 내용은 [Event Handling Guide for UIKit Apps](https://developer.apple.com/library/content/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/index.html#//apple_ref/doc/uid/TP40009541)를 참고하십시오. 661 | * 네트워크로 전송하는 데이터가 많을 수록 많은 전력을 소모하게 되며, 네트워트를 사용하는 작업은 전력 소모에 가장 영향을 많이 기치는 작업입니다. 다음 지침을 따르면 네트워크에 소모되는 시간을 최소화 할 수 있습니다. 662 | * 필요한 경우에만 네트워크 서버에 연결하고 해당 서버를 polling하지 마십시오. 663 | * 네트워트에 연결해 작업을 할때는 압축된 데이터 형식을 사용하여 최소량의 데이터를 전송하십시오. 664 | * `NSURLSession` 클래스를 사용하여 여러개의 파일을 업로드하거나 다운로드 할때, 다음 작업을 하기 위해 이전 작업이 완료되기를 기다리지 말고 queue에 추가하십시오. 시스템이 자동적으로 가장 효율적으로 작업을 실행합니다. 665 | * 가능하다면 Wi-Fi를 사용해 네트워크에 연결하십시오. Wi-Fi는 셀룰러보다 전력 소모가 적습니다. 666 | * `Core Location` 클래스를 이용해 위치 데이터를 수집하는 경우, 최대한 빨리 위치 업데이트를 비활성화 하고 distance filter와 accuracy level을 적절한 값을 설정하십시오. 관련된 자세한 내용은 [Location and Maps Programming Guide](https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009497)를 참고하십시오. 667 | * Instruments는 전력 관련 정보 수집을 위한 여러가지 계측기가 포함되어 있습니다. 이 계측기를 사용하여 전력 소비에 대한 여러가지 정보와 여러 하드웨어(Wi-Fi, Blutooth, GPS, 디스플레이, CPU 등)에 대한 측정 값을 수집 할 수 있습니다. 668 | 669 | --- 670 | 671 | ### Use Memory Efficiently 672 | > 앱은 가능한 적은 메모리를 사용하여 시스템이 많은 메모리를 확보할 수 있도록 해야합니다. 시스템의 사용가능한 여유 메모리와 앱의 성능에는 직접적인 상관 관계가 있습니다. 사용 가능한 메모리가 적으면 이후 메모리 요청에 따른 작업을 수행할때 문제을 일으킬 가능성이 높습니다. 673 | 674 | #### Obseve Low-Memory Warnings 675 | > 시스템에서 앱에 메모리 부족 경고를 보내면 즉시 응답하십시오. 메모리 부족 경고는 필요없는 객체에 대한 참조를 제거할 수 있는 기회입니다. 이 경고에 대해 응답하다 실패하는 경우 앱이 종료 될 수 있기 때문에 주의해야합니다. 시스템은 아래 API를 사용해 메모리 경고를 앱에 전달합니다. 676 | 677 | * `applicationDidReceiveMemoryWarning:` : app delegate 메소드 678 | * `didReceiveMemoryWarning`: UIViewController 메소드 679 | * `UIApplicationDidReceiveMemoryWarningNotification`: 노티피케이션 680 | 681 | * 이러한 경고를 받으면 불필요한 메모리를 즉시 해제해야합니다. 사용하지 않는 거대 데이터 구조가 있는 경우, 해당 구조를 디스크에 저장하고 메모리에서 사본을 제거하십시오. 682 | 683 | * 참고: iOS 시뮬레이터의 `Simulate Memory Warning` 명령을 사용하여 메모리 부족 상태의 앱 동작을 테스트 할 수 있습니다. 684 | 685 | #### Reduce Your App's Memory Footprint 686 | > 초기에 낮은 설치 공간으로 시작해 추후에 앱을 확장 할 수있습니다. 초기 설치 공간을 줄이는 방식에는 다음과 같은 방법이 있습니다. 687 | 688 | * **메모리 릭(leak) 제거** Instruments를 사용하여 실제 디바이스와 시뮬레이터에서 메모리 릭을 추적하십시오. 689 | * **리소스 파일 줄이기** 리소스 파일을 가능한 작게 만들기 위해 모든 이미지 파일을 압축하십시오. (iOS 앱 기본 이미지 포맷인 PNG 이미지를 압축하려면 pngcrush 도구를 사용하십시오.) 690 | * **속성 목록 파일 줄이기** NSPropertyListSerialization` 클래스를 사용하여 속성 목록을 이진법으로 작성할 수 있습니다. 691 | * **대규모 데이터 관리** 대규모 데이터를 관리하는 경우 `Core Data` 혹은 `SQLite`를 사용하십시오. 이는 전체 세트를 한번에 메모리에 저장하지 않고 대용량 데이터를 효율적으로 관리 할수 있는 방법을 제공합니다. 692 | * **리소스 로드 시점** 실제로 필요할 때까지 리소스 파일을 로드하지 마십시오. 리소스 파일을 미리 가져오는 것은 시간을 절약 시키는 방법처럼 보일 수 있지만, 결국은 앱의 속도를 저하시키게 됩니다. 693 | 694 | #### Allocate Memory Wisely 695 | > 다음은 현명하게 메모리를 할당할 수 있는 팁입니다. 696 | 697 | * **리소스에 크기 제한을 두십시오.** 고해상도 이미지를 사용하는 대신 iOS 기기에 적합한 크기의 이미지를 사용하십시오. 대용량 리소스 파일을 사용해야하는 경우에는 파일의 일부분만 로드하는 방법을 사용하세요.(`mmap`, `munmap`) 698 | * **무제한 문제를 다루지 않도록 하십시오.** 제한이 없는 문제는 많은 양의 데이터 계산이 필요할 수도 있습니다. 앱에서 사용 가능한 메모리보다 문제 해결에 더 많은 메모리가 필요 한 경우 계산을 완료하지 못할 수 있습니다. 699 | 700 | --- 701 | 702 | ### Tune Your Networking Code 703 | > iOS의 네트워킹 스택에는 iOS 기기의 무선 통신을 위한 몇가지 인터페이스가 포함되어있습니다. 주요 인터페이스는 `CFNetwork` 프레임 워크이며, `Core Entity`프레임 워크와 `BSD` 소켓을 기반으로 되어있습니다. 704 | > 네트워크 통신을 위해 `CFNetwork` 프레임 워크를 사용하는 방법에 대한 정보는 [ CFNetwork Programming Guide](https://developer.apple.com/library/content/documentation/Networking/Conceptual/CFNetwork/Introduction/Introduction.html#//apple_ref/doc/uid/TP30001132)와 [CFNetwork Framework Reference](https://developer.apple.com/reference/cfnetwork)를 참고하십시오. 705 | 706 | #### Tips for Efficient Networking Using Wi-Fi 707 | > 네트워크를 통해 데이터를 송수신하는 작업은 기기에서 가장 전력을 많이 소모하는 작업 중 하나입니다. 데이터 송수신에 소요되는 시간을 최소화하여 배터리 수명을 향상시키기 위해 아래 팁을 고려하십시오. 708 | 709 | * 데이터 형식을 가능한 컴팩트하게 정의하십시오. 710 | * 수다스러운 프로토콜 사용을 피하십시오. 711 | * 셀룰러 및 Wi-Fi는 활동이 없을때 자동적으로 꺼지도록 설계되어있지만, 앱이 주기적으로 작은 데이터를 전송하는 경우에는 Wi-Fi가 활동하지 않을때도 계속 켜져 전력을 소비할 수 있습니다. 소량의 데이터를 자주 송신하기 보다 대량의 데이터를 긴 간격으로 전송하는 것이 좋습니다. 712 | * 네트워크 동신을 할때 패킷은 언제든지 손실 될 수 있습니다. 따라서 네트워킹 코드를 작성할때 장애 처리와 관련해서는 강력하게 대응하는 것이 좋습니다. 713 | 714 | #### Using Wi-Fi 715 | > 앱이 Wi-Fi를 사용하여 네트워크에 액세스 하는 경우 앱의 Info.plist 파일에 `UIRequiresPersistentWiFi` 키를 포함시켜 시스템에 알려줘야합니다. 이 키가 포함되어 있으면 앱이 실행되는 동안 Wi-Fi 하드웨어를 종료하지 말아야 한다는 것을 의미합니다. 716 | 717 | #### The Airplane Mode Alert 718 | > 기기가 비행기 모드에 있는 동안 앱이 시작되면, 시스템에서 사용자에게 비행모드임을 알리기 위해 alert를 표시할 수 있습니다. 시스템은 다음 조건이 모두 충족되면 alert를 표시합니다. 719 | 720 | * Info.plist 파일에 `UIRequiresPersistentWiFi` 키가 포함되어있고, 해당 키의 값이 `true`일때 721 | * 기기가 비행기 모드에 있는 동안 앱이 실행됨 722 | * 비행기 모드로 전환 한 후, 장치의 Wi-Fi가 수동으로 활성화 됨 723 | 724 | --- 725 | 726 | ### Imporve Your File Management 727 | > 파일 관리를 위해 디스크에 쓰는 데이터 양을 최소화 하는 것이 좋습니다. 파일 관련 작업을 최소하하는 데 도움이 되는 몇가지 팁은 다음과 같습니다. 728 | 729 | * 파일 전체를 저장하는 것이 아니라, 변경된 파일의 일부분만 저장할 수 있도록 하십시오. 730 | * 데이터가 randomly 접근가능하고, 양이 이 몇 MB이상인 경우 `Core Data` 혹은 `SQLite`와 같은 영구 저장소에 저장하십시오. 731 | * 캐시파일을 디스크에 쓰지 않도록 하십시오. 유일한 예외 상황은 앱을 종료했을때와 동일한 상태로 되돌릴 수 있도록 상태 정보를 저장해야 할때 입니다. 732 | 733 | --- 734 | 735 | ### Make App Backups More Efficient 736 | > 백업은 사용자가 iTunes와 기기를 동기화 할때나 iCloud를 통해 무선으로 실행되고, 백업이 진행되는 동안 기기에서 사용자의 컴퓨터 또는 iCloud 계정으로 파일이 전송됩니다. 앱 샌드박의 파일 위치에 따라 해당 파일을 백업/복원할지 여부가 결정되는데, 앱에서 주기적으로 많은 양의 데이터를 만들고 변경하는 경우에는 백업 속도가 느려질 수 있습니다. 파일 관리 코드를 작성할때는 이 사실을 꼭 염두해 두어야합니다. 737 | 738 | #### App Backup Best Practices 739 | > 백업/복원 작업을 위해 앱에서 준비해야 하는 것은 없습니다. iClound나 iTunes에 연결되면 앱 데이터 파일의 변경된 부분을 백업합니다. 하지만 아래 디렉토리의 내용은 백업하지 않습니다. 740 | 741 | \/AppName.app 742 | \/Library/Caches 743 | \/tmp 744 | 745 | **동기화 프로세스에 걸리는 시간과 앱이 차지하는 용량을 줄이기 위해 다음 가이드 라인에 따라 앱 데이터를 저장하는 것이 좋습니다.** 746 | 747 | * 중요한 데이터는 /Documents 에 저장해야합니다. 중요데이터란 사용자 문서 및 기타 사용자가 생성한 콘텐츠와 같이 앱에서 다시 생성 할 수 없는 데이터입니다. 748 | * Support file에는 앱에서 다운로드하거나 재생성가능한 파일이 포함됩니다. 749 | * 캐시된 데이터는 /Library/Caches 디렉토리에 저장되어야 합니다. 캐시 디렉토리에 저장해야하는 파일의 예로는 데이터베이스 캐시 파일, 잡지, 신문, 지도 앱 등에서 다운로드 받은 파일입니다. 750 | * 임시 데이터는 /tmp 디렉토리에 저장해야합니다. 임시 데이터는 오랜 시간 동안 유지할 필요가 없는 데이터로 구성됩니다. 기기에서 사용된 후에는 공간을 차지하지 않도록 파일을 삭제해야합니다. 751 | * 응용 프로그램에서 디렉토리를 사용하는 자세한 방법은 [File Systeom Programming Guide](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010672)를 참고하세요. 752 | 753 | #### Files Saved During App Updates 754 | > 사용자가 앱 업데이트를 다운로드하면 iTunes는 새로운 앱 디렉토리에 업데이트를 설치합니다. 그런 다음 이전 앱을 삭제하기 전에 사용자 데이터 파일을 새 앱의 디렉토리로 이동시킵니다. 아래 디렉토리의 파일은 업데이트 프로세스에서 보존됩니다. 755 | 756 | \/Documents 757 | \/Library 758 | 759 | **업데이트 후에, 다른 디렉토리의 파일도 옮겨질 수 있지만 파일이 존재한다고 믿어서는 안됩니다.** 760 | 761 | --- 762 | 763 | ### Move Work off the Main Thread 764 | > 앱의 main thread에서 수행되는 작업의 유형을 제한해야합니다. main thread는 앱의 터치 이벤트 및 기타 사용자 입력을 처리하는 곳입니다. 앱이 항상 사용자에게 응답할 수 있도록 하려면 네트워크에 액세스하는 작업이나 장시간이 걸리는 작업을 main thread에서 실행 해서는 안됩니다. 대신 백그라운드 스레드에서 옮겨서 작업해야합니다. 이를 수행하는 가장 좋은 방법은 GCD(Grand Center Dispatch) 또는 NSOperation 객체를 사용하여 작업을 비동기(async)로 수행하는 것입니다. 765 | 766 | * 작업을 백그라운드에서 실행시키면 main thread가 자유롭게 사용자 입력을 처리할 수 있게되며, 이는 앱이 시작/종료될때 특히 중요합니다. 767 | * 앱이 실행(launch)될때 main thread가 차단 된 경우 시스템은 실행이 완료되기 전에 앱을 종료(kill)시킬 수 있습니다. 768 | * 앱이 종료될때 main thread가 차단되어있으면 사용자의 중요한 데이터를 기록하기 전에 시스템이 앱을 종료(kill)할 수 있습니다. 769 | * GCD, operation object, thread에 관한 자세한 정보는 [Concurrency Programming Guide](https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091)를 참고하세요. 770 | 771 | --- 772 | 773 | * 원문에서 중복되는 내용이나 예제 코드는 생략했습니다. 정확한 내용은 [원문](https://developer.apple.com/library/content/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html)을 확인해주세요. 774 | * **번역: 전미정** 775 | 776 | [**위로가기**](#위로가기) 777 | --------------------------------------------------------------------------------