iOS2012. 10. 5. 16:37

사운드


사용자는 아이폰에서 자신의 기호와 의도를 따르는 아주 멋진 사운드가 나길 바란다. 사용자는 가끔 설정에서 사운드가 꺼져있을때 조차도 소리가 나길 기대할 경우가 있는데, 이것은 사용자가 자신이 원하는 사운드는 듣고 싶어하고 자신이 원하지 않는 사운드는 듣고 싶어하지 않기 때문이다. 이러한 경향을 따르기 위해 아이폰 OS는 다음과 같은 기능을 지원하는 프로그래밍 인터페이스를 제공한다. 


- 어플리케이션의 사운드가 기기의 다른 사운드들과 어떻게 어울릴 것인지 정의한다

- 사용자의 기대대로 어플리케이션 사운드가 재생되고 있음을 보장한다


어플리케이션에서 사운드를 어떻게 다룰지 결정하기 전에 먼저 주요 설정 상황에서 사용자가 어떤 것을 기대하는지를 이해할 필요가 있다. 



1. 벨/무음(Ring/Silent) 스위치 - 사용자가 기대하는 것


사용자는 다음과 같은 경우에 벨/무음 스위치를 사용한다.


- 전화 벨소리나 문자 도착음 같이 예상하지 못했던 소리에 의해 방해받고 싶지 않을때

- 키보드나 기타 피드백 사운드와 같이 사용자 액션에 따른 소리를 듣고 싶지 않을때

- 사용자 액션의 주 목적이 아닌 게임 배경음이나 효과음 등을 듣고 싶지 않을때


예를 들어 극장에서는 다른 사람들을 방해하지 않기 위해 벨 소리를 끈다. 이 상황에서 사용자는 여전히 어플리케이션을 사용하고 싶어하지만 벨 소리같은 갑작스런 소리에 의해 놀라고 싶지는 않을 것이다. 


그러나 벨/무음 스위치는 사용자 액션이 직접적으로 소리에 관련된 것이거나, 사용자가 명시적으로 요청한 소리라면 이를 차단하지 않는다. 예를 들면,


- 미디어 재생 전용 어플리케이션에서 미디어를 재생하는 것은 사용자가 재생을 명시적으로 요청한 것이므로 차단하지 않는다.

- 시계의 알람은 사용자가 명시적으로 설정한 것이므로 차단하지 않는다.

- 언어 학습 어플리케이션에서의 음성을 재생하는 것은 사용자가 명백히 그것을 들으려 한 것이므로 차단하지 않는다.

- 음성 채팅 어플리케이션에서의 대화는 사용자가 음성 채팅이라는 단 하나의 목적을 가지고 어플리케이션을 시작하는 것이기 때문에 차단하지 않는다.


이러한 특성은 사용자 컨트롤 원칙을 따른다. 사용자가 명시적으로 요청한 소리를 들려주는 것이 적당한지 아닌지를 결정하는 것은, 기기가 아닌 사용자에게 달려 있기 때문이다.



2. 볼륨 조절 버튼 - 사용자가 기대하는 것


기기에서 나는 모든 소리는 볼륨 조절 버튼을 사용해 조절할 수 있다. 이는 벨/무음 스위치가 켜져있는지 꺼져있는지에 상관없이 어떤 소리든 언제라도 음량을 줄일 수 있다는 것을 의미한다.


어떤 경우에는 어플리케이션의 사용자 인터페이스를 통해 사용자가 볼륨을 조절할 수 있게 하는 것이 적절할 수도 있다. 예를 들어, YouTube에서는 슬라이더 컨트롤을 통해 현재 보고있는 비디오의 볼륨을 조절한다. YouTube가 실행 중인 동안에는 슬라이더와 볼륨 조절 버튼 둘 다 비디오 볼륨에 영향을 미친다. 이것은 어플리케이션이 실행되는 동안 슬라이더가 볼륨 조절 버튼의 프록시 역할을 하기 때문이다. 슬라이더는 어플리케이션의 볼륨과 전체 시스템 볼륨에 영향을 미치며 벨 소리에는 영향을 미치지 않는다.


이와 마찬가지로 볼륨 조절 버튼으로 어플리케이션이 현재 재생 중인 오디오를 조절하면 전체 시스템 볼륨도 같이 조절되며, 벨 소리에는 영향을 미치지 않는다. (오디오가 재생되지 않는 상태에서는 볼륨 조절 버튼으로 벨 소리 크기를 조절할 수 있다.)


이러한 특성 역시 사용자 컨트롤의 원칙을 따르는데, 이것은 기기에서 얼마나 큰 소리가 나야할지 결정하는 것은 언제나 사용자이기 때문이다.


가끔은 어플리케이션 내에서 상대적이거나 독립적인 볼륨 레벨을 사용할 수도 있지만, 이 경우에도 최종 오디오 출력은 볼륨 조절 버튼을 사용하든 어플리케이션 컨트롤을 사용하든 상관없이 항상 시스템 볼륨을 따라야 한다. 이것은 어플리케이션의 오디오 출력에 대한 제어 권한은 언제나 사용자에게 있음을 의미한다.



3. 헤드셋과 헤드폰 - 사용자가 기대하는 것


사용자가 헤드셋이나 헤드폰을 연결한다는 것은 현재 재생중인 오디오를 계속해서 듣되 개인적으로만 듣기를 원하는 것이다. 그렇기 때문에 사용자는 오디오가 중지되지 않고 계속해서 재생되길 원할 것이다.


반대로 사용자가 헤드셋이나 헤드폰을 빼는 경우에는 자신이 듣고 있던 것이 남에게 자연스레 알려지길 원하지 않을 것이다. 그렇기 때문에 어플리케이션은 현재 오디오 재생을 중지시키고 사용자로 하여금 명시적으로 재생을 다시 시작하게 해야 한다.



4. 어플리케이션의 오디오 특성 정의


어플리케이션에서 소리를 내거나 녹을을 하려면 그 어플리케이션의 오디오 특성이 기기의 오디오 환경과 어떻게 잘 어울릴 것인가를 결정해야 한다. 대부분의 어플리케이션에서 이는 아이폰 OS가 정의한 표준 인터랙션을 받아들이는 것을 의미하는데, 이러한 인터랙션은 시스템 사운드 서비스(System Sound Services)에 의해 지원되며 시작음이나 피드백, 경고음과 같은 부수적인 사운드만을 재생하는 어플리케이션에 잘 어울린다. 


그러나 어플리케이션의 주 기능으로 오디오를 재생, 녹음 하거나 긴 사운드트랙을 재생하는 상황에서는 표준 인터랙션이 적절하지 않다. 이 경우에는 어플리케이션의 오디오가 시스템 오디오 환경과 어울리는 방식에 영향을 줄 수 있는 오디오 특성 그룹을 정의할 수 있다. 오디오 세션 서비스(Audio Session Services)로 이러한 오디오 특성을 정의할 수 있다.


어떠한 특성을 정의하더라도 전화 기능은 현재 실행 중인 어플리케이션을 중단시킬 수 있다. 모든 어플리케이션은 사용자가 걸려온 전화를 받는 것을 막아서는 안된다.


1) 시스템 사운드 서비스(System Sound Services)


어플리케이션의 기능에 부차적인 짧은 소리를 재생할 때는 시스템 사운드 서비스를 사용한다. 구체적으로 다음과 같은 경우들이 이에 해당한다.


- 어플리케이션에서 경고음만을 재생하는 경우

- 30초 이내로 재생되는 경우

- 사운드의 레벨이나 위치 조정이 필요하지 않은 경우

- 언제나 기기에서 재생되는 다른 사운드들과 섞일 수 있는 경우

- 항상 벨/무음 스위치를 따라야 하는 경우


다음은 시스템 사운드 서비스에 정의되어 있는 함수들이다.


AudioServicesPlaySystemSound: 벨/무음 스위치를 따름. 다른 사운드와 섞일 수 있음. 예) 탭에 대한 피드백, 짧은 시작음

AudioServicesPlayAlertSound: 벨/무음 스위치를 따름. 다른 사운드와 섞일 수 있음. 예) 실패 경고음 혹은 새 메시지 알림음


NOTE: 기기 설정에서 진동이 켜져 있을 시, AudioServicesPlayAlertSound는 기기를 진동시킨다.


AudioServicesPlayAlertSound는 되도록 적게 사용하도록 하고, 사용자에게 상황을 알려주는 것이 적당한 경우에만 사용하도록 한다.


2) 오디오 세션 서비스(Audio Session Services)


어플리케이션의 오디오 특성에 대한 특정 그룹을 정의하는 경우 오디오 세션 서비스를 사용한다. 다음과 같은 경우가 이에 해당한다.


- 미디어 재생 어플리케이션이나 톤-매칭 게임과 같이 사운드가 어플리케이션의 주요 부분인 경우

- 30초 이상 재생되는 경우(어플리케이션에 필수적인 사운드가 아닌 경우도 포함)

- 사운드의 레벨이나 위치 조정이 필요한 경우

- 다른 어플리케이션의 사운드와 섞이지 않아야 하는 경우


간단하게 설명하면, 아이폰 OS는 오디오 세션을 사용하여 어플리케이션의 오디오가 기기에 어떻게 어울릴 것인지 결정하는 것을 도와준다. 오디오 세션을 사용하면 다음을 지정하는 것도 가능하다.


- 다른 소스로부터 얻은 오디오와 섞을 수 있는지 여부

- 벨/무음 스위치가 켜져 있는 경우에도 오디오를 재생할 수 있는지 여부


오디오 세션은 헤드셋 연결이 제거되는 것 같이 하드웨어적인 오디오 경로가 변화하는 경우나 강제 중단되는 경우에 이를 잘 처리할 수 있도록 노티피케이션을 제공한다.


어플리케이션의 오디오 특성 그룹을 정의하기 위해서는 오디오 세션 카테고리를 지정한다. 아이폰 OS는 7개의 카테고리를 제공하는데, 각각의 카테고리는 일정한 특성 그룹을 캡슐화한다. 카테고리를 적절히 지정하면 아이폰 OS가 그에 맞게 사운드를 제어해주어 사용자에게 더욱 좋은 경험을 제공할 수 있다.


대다수의 어플리케이션들은 하나의 카테고리만을 사용하며, 녹음과 재생같이 서로 매우 다른 방법으로 오디오를 사용하는 어플리케이션에 대해서만 하나 이상의 카테고리를 사용한다.


NOTE: 모든 어플리케이션에서 카테고리는 한번에 하나만 활성화 된다.


오디오 세션은 다음과 같은 오디오 프로그래밍 인터페이스에 의해 재생되는 사운드를 다룬다.


- Audio Queue Services

- OpenAL

- I/O 오디오 유닛

- AVAudioPlayer 클래스


짧거나 부가적인 사운드에 대해서는 시스템 사운드 서비스를 사용할 수도 있지만, 이 경우 오디오 세션이 어떤 식으로든 시스템 사운드 서비스가 재생하고 있는 사운드를 제어하고 있지는 않는지 확인해야 한다. 


다음은 오디오 세션 카테고리에 대한 설명이다.


UserInterfaceSoundEffects: 벨/무음 스위치를 따름. 다른 사운드와 섞일 수 있음. 예) 탭에 대한 피드백, 시작음

AmbientSound: 벨/무음 스위치를 따름. 다른 사운드와 섞일 수 있음. 예) 부가적인 소리 및 잡음

SoloAmbientSound: 벨/무음 스위치를 따름. 다른 사운드와 섞일 수 없음. 예) 게임 사운드트랙

MediaPlayback: 벨/무음 스위치를 따르지 않음. 다른 사운드와 섞일 수 없음. 예) 노래, 비디오, 스트리밍 오디오

LiveAudio: 벨/무음 스위치를 따르지 않음. 다른 사운드와 섞일 수 없음. 예) 음악이나 실시간으로 사용자가 만든 사운드

RecordAudio: 벨/무음 스위치를 따르지 않음. 다른 사운드와 섞일 수 없음. 예) 사용자 녹음

PlayAndRecord: 벨/무음 스위치를 따르지 않음. 다른 사운드와 섞일 수 없음. 예) 음성 변조 어플리케이션과 같이 동시에 오디오를 입출력하는 경우


NOTE: 오디오 세션 카테고리를 지정하지 않을 경우의 디폴트는 단독 배경음(solo ambient) 카테고리이다.



5. 복합적으로 사용하기


다음의 세가지 시나리오는 사용자에게 좋은 경험을 제공하기 위해 서로 다른 사운드 서비스를 어떻게 사용할 수 있는지를 보여준다.


[시나리오 1]


여러분이 블로깅 어플리케이션을 개발중이라고 가정해보자. 사용자는 텍스트와 이미지를 웹으로 올릴 수 있다. 짧은 시작음과 사용자 액션(포스팅이 완료되었을 때와 같은)에 따른 다양한 짧은 효과음들, 혹은 포스팅이 실패 했을때는 경고음을 들려주려 한다.


이러한 어플리케이션에서 사운드는 부가적이다. 주 작업은 오디오와는 아무런 관계가 없고 사용자는 소리 없이도 어플리케이션을 잘 이용할 수 있다. 이런 시나리오에서는 시스템 사운드 서비스를 사용해야 한다. 


[시나리오 2]


여러분은 새로운 언어를 학습할 수 있는 교육용 어플리케이션을 개발중이다. 어플리케이션이 시작되면 시작음을 들려주고, 사용자가 특정한 컨트롤을 누르면 피드백 사운드를 들려줄 것이다. 또한 사용자는 올바른 발음을 확인하기 위해 녹음된 단어나 문구를 들어볼 수 있다. 이렇게 서로 다른 사운드를 사용자가 기대하는 대로 들려주려면 다음을 따른다.


- 어플리케이션 시작음이나 피드백 사운드를 재생할때는 시스템 사운드 서비스를 사용한다.

- 미디어 재생(media playback) 카테고리를 적용한다. 녹음된 단어 등을 들려주는 것은 이 어플리케이션의 주 기능이기 때문이다.


이렇게 하면 벨/무음 스위치가 꺼져 있는 경우 시작음이나 피드백 사운드는 들리지 않는다. 그러나 사용자가 컨텐츠를 듣기 위해 명시적으로 선택하는 경우는 그것을 들을 수 있다.


[시나리오 3]


화면상의 캐릭터가 다양한 임무를 수행하는 게임의 경우를 생각해보자. 시작음이나 효과음, 사운드트랙 등을 들려줄 수 있다. 이 경우 사용자가 기대하는 사운드를 들려주기 위해서는 다음을 따른다.


- 어플리케이션 시작시에는 시스템 사운드 서비스를 사용한다.

- 단독음(ambient solo) 카테고리를 지정한다. 왜냐하면 사운드트랙이나 효과음은 중요한(그러나 필수적이지는 않은) 어플리케이션 경험의 일부이기 때문이다.


이렇게 하면 벨/무음 스위치가 꺼져 있는 경우 시작음이나 효과음, 사운드 트랙 등은 들리지 않는다. 그러나 음악(iPod)에서 노래를 재생하는 도중에 게임을 시작한다면 노래가 멈추고 사운드트랙과 효과음 등이 들린다.

Posted by 다오나무
iOS2012. 10. 5. 12:04

iPhone OS에서 실행되는 어플리케이션은 Core OS와 Core Services 프레임워크를 분류하여 로컬 파일시스템과 네트워크에 접근할 수 있습니다.

또한 사용자의 데이터를 저장하거나 다음 사용을 위한 어플리케이션의 상태를 저장하기 위해 파일을 읽고 쓰는 것이 가능합니다.

네트워크에 접근함으로써 네트워크상의 서버와 통신하거나 데이터를 주고 받는 등의 원격 작업을 수행할 수 있는 기능을 갖출 수 있습니다.

iPhone OS의 파일은 사용자들의 미디어파일과 개인정보와 같은 파일들과 함께 Flash 메모리를 공유하여 사용하고 있습니다.

보안상의 이유로 개발자가 만든 어플리케이션은 자신이 위치한 자신의 디렉토리에 국한하여 제한적인 데이터 읽기, 쓰기만을 할 수 있습니다.

Commonly Used Directories

보안을 위해 어플리케이션은 몇몇에 불과한 디렉토리에 접근하여 데이터와 환경 설정을 읽고 쓸수 있습니다.

어플리케이션이 장치에 설치될때 어플리케이션을 위한 홈 디렉토리가 생성됩니다. 

다음은 그 내부의 중요한 서브디렉토리의 설명입니다.

<Application_Home>/AppName.app

이 디렉토리는 어플리케이션 자신을 포함하는 Bundle 디렉토리입니다.
실행중에 이 디렉토리 내부의 파일을 변경할 수 없습니다. 
iPhone OS 2.1 혹은 그 이후의 버젼은 iTunes에서 이 디렉토리를 백업하지 않습니다.
그러나 어플리케이션을 구매했을 당시의 초기 싱크 과정에서는 컨텐츠 내용이 복사됩니다.

<Application_Home>/Documents/

이 디렉토리는 어플리케이션이 특정 데이터를 저장하기 위해 사용되는 공간입니다.
사용자의 데이터나 다른 정보를 정기적으로 저장할 수 있습니다.
이 디렉토리 내부의 컨텐츠는 iTunes에 의해서 백업 됩니다.

<Application_Home>/Library/Preferences

이 디렉토리는 어플리케이션의 특정 설정 파일을 포함합니다.
하지만 환경 설정 파일을 직접 생성하여서는 안되고 NSUserDefaults 클래스나 CFPreferences API를 사용해야 합니다.
이 디렉토리 내부의 컨텐츠는 iTunes에 의해서 백업 됩니다.

<Application_Home>/Library/Caches

이 디렉토리는 어플리케이션의 실행때마다 지속적으로 사용해야 하는 파일을 읽고 쓰기 위해 사용합니다.
개발한 어플리케이션은 일반적으로 이곳에 파일을 추가하고 삭제하여야 합니다.
iTunes는 전체 복원시에 이 디렉토리의 내용을 모두 제거 합니다.
그러므로 어플리케이션은 필요할때마다 이곳의 파일을 생성해 낼 수 있어야 합니다.
iPhone OS 2.2 혹은 그 이후의 버젼은 iTunes에서 이 디렉토리를 백업하지 않습니다.

<Application_Home>/tmp/

이 디렉토리는 어플리케이션이 실행때마다 지속될 필요가 없는 임시적인 파일을 읽고 쓰기 위해 사용합니다.
어플리케이션이 실행중이 아닐때 시스템은 파일이 더 필요한가를 판단하여 더이상 필요하지 않다고 판단이 되면 삭제합니다.
iPhone OS 2.1 혹은 그 이후의 버젼에서는 iTunes에서 이 디렉토리를 백업하지 않습니다.

Backup and Restore

어플리케이션이 백업과 복원을 위해 따로 준비해야 하는 것은 없습니다.

iPhone OS 2.2 혹은 그 이후의 버젼은 장치가 컴퓨터에 연결되어 싱크 될때 다음을 제외한 나머지 모든 파일을 증분 백업 합니다.
<Application_Home>/AppName.app
<Application_Home>/Library/Caches
<Application_Home>/tmp

어플리케이션이 매우 큰 파일을 생성하거나 매우 빈번하게 파일 엑세스를 한다면 /Documents가 아닌 /Library/Caches를 이용하는 것이 좋습니다. /Documents에 저장하게 되면 백업/복원 작업시에 시간이 더 걸리게 되는 문제점이 될 수도 있습니다.

Getting Path to Application Directories

다양한 레벨의 시스템에서 어플리케이션의 샌드박스의 위치를 알아내기 위한 다양한 프로그래밍 방식이 있어왔습니다.

하지만 Cocoa는 이러한 경로를 탐색하기 위해 다양한 프로그래밍 인터페이스를 제공합니다.

NSHomeDirectory(Foundation 프레임워크에 포함) 함수는 홈디렉토리의 경로뿐만 아니라 Documents, Library 그리고 tmp같은 디렉토리 경로를 손쉽게 얻어올수 있습니다.

또한 추가적으로 NSSearchPathForDirectoriesInDomains와 NSTemporaryDirectory함수를 사용하여 정확한 Document, Caches, tmp 디렉토리 경로를 얻어올 수 있습니다.

이 NSSearchPathForDirectoriesInDomains 함수를 사용하여 어플리케이션과 연관된 전체 경로를 알 수 있습니다.

iPhone OS에서 이 기능을 사용할려면 적절한 검색 경로를 첫번째 매개 변수로, NSUserDomainMask를 두번째 매개 변수로 지정합니다.

일반적으로 자주 사용되는 경로 상수는 다음과 같은 것들이 있습니다.

NSDocumentDirectory
<Application_Home>/Documents

NSCachesDirectory
<Application_Home>/Library/Caches

NSApplicationSupportDirectory
<Application_Home>/Library/Application Support


어플리케이션의 Documents/ 디렉토리를 찾기 위해 다음과 같이 사용합니다.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

위의 결과값을 찍어보면 /var/mobile/Applications/해쉬코드/Documents 와 같은 값이 나옵니다. 해당 경로가 어플리케이션 Documents 디렉토리의 절대 경로가 되겠죠.

두번째 인자인 NSUserDomainMask말고 다른것을 사용할 수 있습니다. 

NSSystemDomainMask와 첫번째 인자로 NSApplicationDirectory로 검색하여 보면 /Applications 라는 시스템 경로를 얻을 수 있습니다.

Reading and Writing File Data

iPhone OS는 파일을 읽고 쓰고 관리할 수 있도록 몇가지 방법을 제공하고 있습니다.

Foundation Framework :
  • 어플리케이션이 Property List를 사용한다면 NSPropertyListSerialization API를 사용하여 NSData로 변환이 가능합니다.  이렇게 변환 후에 NSData의 메서드를 이용하여 데이터를 쓸 수 있습니다.
  • 어플리케이션의 Model객체가 NSCoding 프로토콜을 채택하였다면 NSKeyedArchiver 클래스를 이용하여 객체를 저장할 수 있습니다.
  • Foundation 프레임워크는 컨텐츠 파일의 랜덤 엑세스를 위한 NSFileHandle 클래스를 제공합니다.
  • Foundation 프레임워크안의 NSFileManager는 시스템에 있는 파일을 생성하고 조작하는 메서드를 제공합니다.

Core OS calls :

  • fopen, fread, fwrite 를 호출하여 데이터를 엑덤 엑세스를 통해 읽고 쓸 수 있습니다.
  • mmap과 munmap을 호출하여 효과적으로 큰 파일을 메모리로 로드하거나 그안의 컨텐츠에 접근할 수 있습니다.

Reading and Writing Property List Data

Property List는 캡슐화 되어있는 데이터를 말합니다. 배열, 문자열, 날짜, 이진데이터, 숫자 및 Boolean 값을 포함합니다.

다른 예로 모든 Cocoa/iPhone 어플리케이션의 설정이 들어있는 Info.plist 파일을 들 수 있습니다.

코드상에서는 NSDictionary, NSArray, NSString, NSDate, NSData, NSNumber를 사용할 수 있습니다.

다음은 Property List를 NSData로 변환하여 저장하는 방법입니다.

- (BOOL)writeApplicationPlist:(id)plist toFile:(NSString *)fileName {
   
NSString *error;
   
NSData *pData = [NSPropertyListSerialization dataFromPropertyList:plist
                              format
:NSPropertyListBinaryFormat_v1_0 errorDescription:&error];
   
if (!pData) {
       
NSLog(@"%@", error);
       
return NO;
   
}
   
return ([self writeApplicationData:pData toFile:(NSString *)fileName]);
}
- (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
   
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
   
NSString *documentsDirectory = [paths objectAtIndex:0];
   
if (!documentsDirectory) {
       
NSLog(@"Documents directory not found!");
       
return NO;
   
}
   
NSString *appFile = [documentsDirectorystringByAppendingPathComponent:fileName];
   
return ([data writeToFile:appFile atomically:YES]);
}

그러면 읽어와야 겠죠. 다음의 코드를 참고하세요.
- (id)applicationPlistFromFile:(NSString *)fileName {
   
NSData *retData;
   
NSString *error;
    id retPlist
;
   
NSPropertyListFormat format;
    retData
= [self applicationDataFromFile:fileName];
   
if (!retData) {
       
NSLog(@"Data file not returned.");
       
return nil;
   
}
    retPlist
= [NSPropertyListSerialization propertyListFromData:retData
                  mutabilityOption
:NSPropertyListImmutable format:&format errorDescription:&error];
   
if (!retPlist){
       
NSLog(@"Plist not returned, error: %@", error);
   
}
   
return retPlist;
}
- (NSData *)applicationDataFromFile:(NSString *)fileName {
   
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
   
NSString *documentsDirectory = [paths objectAtIndex:0];
   
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
   
NSData *myData = [[[NSData alloc] initWithContentsOfFile:appFile] autorelease];
   
return myData;
}

id는 객체 자신을 가리키는 타입입니다. 무엇이든 가리킬 수 있는 자바의 Object라고 생각하시면 이해가 쉬울까요.

Using Archivers to Read and Write Data

실제로 프로그램이 실행할때 메모리에 수많은 객체를 생성합니다. 그리고 각각의 객체는 서로 연결되어있습니다.

이러한 객체를 파일로 저장후에 다시 읽었을때 연결된 다른 객체가 존재하지 않는다면 큰 문제가 되겠죠.

아카이브라 불리는 이 과정은 실행중에 생성된 객체들의 복잡한 상속관계를 나타내는 그래프를 모두 바이트 단위로 변환하는 과정입니다.

이것을 사용하기 위해서는 클래스가 NSCoding을 구현해야 하고 그에 따른 encodeWithCode와 initWithCoder 메서드를 구현해야 합니다.

자세한 내용은 관련 [문서]를 참고하세요. 데이터를 저장하기 위해서는 다음과 같은 방식으로 합니다.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[_myDataSource representation]];
[data writeToFile:myFilePath atomically:YES];

데이터를 읽어 들여 복원할때는 다음과 같이 하면 됩니다.
NSData* data = [NSData dataWithContentsOfFile:myFilePath];
id rootObject
= [NSKeyedUnarchiver unarchiveObjectWithData:data];

File Acess Guidelines

파일을 생성하고 데이터를 쓸때 다음의 가이드 라인을 지키도록 합시다.

파일을 쓰는 횟수를 최소화 해야 합니다. 파일을 엑세스 하는 작업은 느리고 제한적인 수명을 가진 플래시 메모리에 하는 행위입니다.

  • 파일의 일부분이 변경되었을때 바뀐 부분만을 쓸 수 있습니다. 적은 바이트의 변경을 위해 전체 파일을 쓰는 행위를 피하도록 합시다.
  • 파일 포맷을 정의할때, 자주쓰이는 데이터를 최대한 하나의 그룹으로 묶어 저장하면 디스크 엑세스 횟수를 최소화 할 수 있습니다.
  • 랜덤한 엑세스가 필요한 데이터 구조로 되어있는 경우 SQLite 데이터베이스에 데이터를 저장할 수 있습니다.

캐쉬 파일을 디스크에 쓰는것을 피하도록 합니다. 어플리케이션이 종료될때 다음 실행시에 동일한 상태로 시작하기 위해 저장하는 것은 예외로 합니다.

Saving State Information

사용자가 Home 버튼을 누르게 되면 iPhone OS는 당신의 어플리케이션을 종료하고 홈스크린 화면으로 돌아갑니다.

마찬가지로 URL을 여는 경우 어플리케이션이 종료하고 다른 어플리케이션의 URI가 열리게 됩니다.

이 과정은 멀티테스트 환경과 달리 현재 실행되는 어플리케이션이 종료되고 다른 어플리케이션이 수행되는 것을 뜻합니다.

이러한 작업이 자주 일어난다면 어플리케이션의 상태를 관리하는 방법을 변경할 필요가 있습니다.

사용자가 수동으로 디스크에 저장하는 작업과 달리 주요 지점에서 자동으로 저장하도록 프로그램이 변경되어야 합니다.

어플리케이션이 종료될 때 임시 캐시 파일이나 데이터베이스 환경을 이용하여 상태를 저장해야 합니다.

다음에 어플리케이션이 실행될때 저장되었던 정보를 가지고 이전 상태로 복원하는 과정을 수행하여야 합니다.

저장하는 횟수를 최소화 하여야 하지만 최대한 적절한 시점에 저장하여 이 상태를 그대로 복원하여 보여주어야 합니다.

예를 들어 연락처를 수정하고 있다가 어플리케이션을 종료하고 다시 실행했을 때 연락처의 가장 첫화면보다 수정하던 창을 그대로 보여주는 것이 좋습니다.

Networking

iPhone OS의 네트워킹 스택은 아이폰과 아이팟 터치에 있는 무선 하드웨어 장치의 여러 인터페이스를 포함합니다.

주요 프로그래밍 인터페이스로는 BSD소켓으로 만들어진 CFNetwork 프레임워크가 있습니다.

이 문서에서는 구체적인 조언만을 담고 있고 NSStream 클래스를 사용하는 방법의 정보를 원하시면 Foundation Framework 문서를 참고하시기 바랍니다.

Tip for Efficient Networking
네트워크를 통해 데이터를 주고받는 행위는 장치의 많은 전력을 소비하는 행위라는것을 기억하셔야 합니다.
데이터를 주고받는 시간을 최소화 하는 것이 배터리 수명에 도움이 됩니다.

  • 통신 프로토콜을 정의할때 데이터 포맷은 가능한한 작게 만들어야 합니다.
  • 채팅과 같은 무수히 많은 통신이 오가는 방식은 피하도록 합니다.
  • 데이터는 하나의 덩어리로 묶어 보낼 수 있습니다.

Cellular와 Wi-Fi를 이용한 통신은 아무런 행동이 없을때 파워가 꺼지도록 만들어져 있습니다. 하지만 계속해서 작은 용량의 패킷을 주고 받게 되면 이것은 지속적으로 파워가 켜져있게 되는 것을 의미하게 되며 배터리가 소모된다는 것을 뜻합니다.

그러므로 작은 데이터를 자주 주고 받는것보다는 큰 데이터를 긴 시간차를 두고 주고 받는 것이 좋습니다.

네트워크를 이용한 통신 프로그램을 작성할때는 패킷의 손실이 일어날 수 있다는 것을 기억해 두어야 합니다.

코드를 작성할때 통신 실패에 대한 핸들링을 충분히 하여야 합니다. 

그 예로 네트워크가 갑자기 사라지게 될 경우 사용자에게 알리는 시스템을 갖추는 등의 노력이 필요합니다.

'iOS' 카테고리의 다른 글

AVAudioSession 카테고리  (0) 2012.10.05
Home, Temporary, Documents, Cache Directory Path 얻기  (0) 2012.10.05
[iPhone] NSString URL 인코딩/디코딩  (0) 2012.10.05
Cycript 소개  (0) 2012.10.04
iOS - OTA ( Over the Air AdHoc )  (1) 2012.10.04
Posted by 다오나무