본문 바로가기
프로그래밍 놀이터/iOS

[Objective-C] 어플리케이션 구조

by 돼지왕 왕돼지 2018. 1. 8.
반응형

 [Objective-C] 어플리케이션 구조


출처 : OS X 구조를 이해하면서 배우는 Objective-C Chap 16.


Notice : 정리자(돼지왕 왕돼지)가 remind 하고 싶은 내용이나 모르는 내용 기반으로 정리하는 것이기 때문에 구체적인 내용은 책을 사서 보시기를 권장드립니다.


16.1. 애플리케이션 번들


* 16.1.1. 애플리케이션 번들 구조


-

Cocoa 앱은 실행 파일이나 필요한 리소스 일체가 하나의 디렉토리 구성으로 저장된다.

이것을 앱 번들(application bundle), 앱 랩퍼(wrapper) 또는 앱 패키지라고 부른다.



-

Mac OS X 는 서브 디렉터리가 많이 작성되지만, iOS는 실행 파일이나 각종 리소스도 비교적 구별 없이 저장된다.

양쪽에 Info.plist 파일이 있는데, 이 파일은 프로퍼티 리스트 형식으로 앱과 관련된 중요한 정보가 담겨 있다.

PkgInfo 파일에는 Mac OS 의 파일 타입과 작성자에 해당하는 정보가 있다.



-

아이폰이나 아이패드 등의 iOS 앱은 아이튠즈로 내려받으면 자신의 홈 디렉터리 아래의 Music/iTunes/Mobile Applications 라는 디렉터리에 저장되어 디바이스와 동기화된다.

앱은 ipa 확장자이지만 실제로는 zip 으로 압축된 파일이므로 압축을 풀면 내용을 볼 수 있다.

하지만 앱은 암호로 서명되어 있으므로 변경하면 동작하지 않는다.




* 16.1.2. nib 파일과 각종 언어 리소스


-

GUI 정의는 Xcode Interface Builder 로 만들어서 nib 파일이라고 부르는 파일에 써 넣는다.

nib 파일은 확장자가 nib 이지만 이것은 Next Interface Builder 의 약어로, NeXTstep 에서 유래되었다.



-

nib 파일에는 앱 메뉴나 윈도우 위에 있는 부품 배치 등의 정보가 아카이브되어 실행 중에 동적으로 읽을 수 있다.



-

nib 파일은 확장자가 ‘nib’ 인 것과 ‘xib’인 것이 있는데, xib 의 실체는 XML 파일이다.

저장된 정보는 동일하며 앱이 빌드될 때 확장자가 nib 인 리소스 파일로 앱 안에 저장된다.



-

사용하는 언어에 관계없이 공통으로 사용하는 리소스는 Mac OS X 라면 Resources 아래에, iOS 라면 앱 번들 아래에 둔다.

선택된 언어에 따라 전환하고 싶은 리소스는 ‘언어명.lproj’ 이라는 디렉터리에 모아서 저장한다.

언어명은 ISO 언어 코드를 이용해서 영어는 en, 일본어는 ja, 한국어는 ko 가 된다.

또한 확장자 lproj 는 language project 에서 따온 것이다.



-

앱을 특정 언어에 맞게 대응하는 것을 지역화(localize)라고 한다.




* 16.1.3. 정보 파일의 주요 내용


-

앱 번들 안의 정보 파일 Info.plist 는 프로퍼티 리스트로, 앱 실행에 꼭 필요한 정보가 담겨 있다.

Xcode 로 프로젝트를 작성하면 파일명이 “프로젝트명 - Info.plist” 인 편집용 파일이 된다.

앱을 빌드할 때 이 파일을 기준으로 앱 번들 안에 Info.plist 가 생성된다.



-

정보 파일 안에 키 CFBundleIdentifier 로 지정된 문자열을 앱 식별명 (Application Identifier) 라고 부른다.

시스템에서 그 앱을 고유하게 식별하는 목적으로 사용된다.

다른 것과 중복되지 않도록 자바 패키지 방식으로 정하는 걸 권장한다.



-

키 접두사 중에서 LS 는 Launch Services 를 의미한다.



-

프로퍼티 리스트의 실제 키와 XCode 로 표시된 문자열이 다를 수 있다.

예를 들어 위에서 본 키 CFBundleIdentifier 는 'Bundle identifier' 처럼 표시될 수 있다. (Xcode 명이라고 한다.)

원래 키를 표시하려면 Xcode 일 경우 오른쪽 클릭으로 콘텍스트 메뉴를 표시해서 ‘Show Raw Keys/Values’ 를 선택한다.



-

책 427p ~ 429p 는 Info.plist 에서 사용하는 key/value 에 대한 설명이 있다.




* 16.1.4. NSBundle 과 리소스 접근


-

NSBundle 은 각종 번들에 대한 인터페이스를 제공하는 클래스로, 지정한 번들 안에서 GUI 를 정의한 nib 파일이나 이미지, 음성, 로드 가능한 코드 등을 찾을 수 있다.



-

여러 가지 Method 들이 있지만, 아래 메소드가 많이 사용된다.


-(NSString*) pathForResource: (NSString*)name ofType:(NSString*)extension

     리시버 번들 안에서 name 으로 지정한 이름과 extension 으로 지정한 확장자를 가진 리소스의 완전 경로명을 돌려준다. 파일에 확장자가 없을 경우 extension 에는 nil 또는 @“” 을 지정한다.

     URLForResource:withExtension: 도 있다.


메서드 pathForResource:ofType: 은 번들 안에서 우선 실행 환경에서 선택된 언어에 대응하는 서브 디렉터리를 순서대로 검색해서 찾지 못하면 Resources 바로 아래(iOS 는 앱 번들 아래)를 검색한다.

이런 동작은 NSBundle 을 사용해서 리소스를 탐색하는 메서드의 공통적인 동작이다.



-

리소스가 저장된 경로를 취득하는 메서드로 resourcePath 가 있지만 이것을 사용해서 다음처럼 리소스 경로를 만드는건 추천하지 않는다.

지역화에 대응하지 못하기 때문이다.

NSString* bundlePath = [[NSBundle mainBundle] resourcePath];

imgPah = [bundlePath stringByAppendingPathComponent:@“test.jpg”];




* 16.1.5. iOS 와 리소스 접근


** 리소스를 디바이스별로 준비하기


-

아래 형태의 파일명을 사용하면 된다.


파일명~다바이스.확장자



-

디바이스 부분에는 다음 중 하나를 지정할 수 있다.

     iphone

     ipad




-

MyResource~iphone.nib, MyResource~ipad.nib 형태의 리소스가 있다면, 아이폰에서 실행할 때는 MyResource.nib 을 로드하면 MyResource~iphone.nib 이 로딩된다.


이런 기법은 이미지나 사운드 같은 다른 리소스에서도 사용할 수 있다.




** 고해상도 이미지 준비하기


-

파일명@2x.확장자

파일명@2x~디바이스.확장자




** 정보 파일의 키문자열로 디바이스 지정하기


-

UIInterfaceOrientation~ipad


키 문자열 뒤에 '~디바이스’ 를 적으면 그 디바이스에만 적용되는 정보가 된다.



-

아래 중 하나를 지정할 수 있다.

 

     iphone

     ipod

     ipad 




* 16.1.6. 유니버셜 바이너리


-

유니버셜 바이너리(universal binary)란 서로 다른 아키텍처를 지닌 복수의 CPU 에서 동작하도록 작성된 실행 파일 형식으로, 애플 고유의 용어이다.

Mac OS X 에서는 파워 PC 맥에서도 인텔 맥에서도 동작이 가능하고 iOS 의 경우에는 프로세서 세대가 다른 아이폰에서도 각자 최적의 동작이 가능하다.

원리는 간단한데, 각각의 CPU 에 대응하는 기계어 코드를 하나의 파일에 담아 실행할 때 적절한 것을 선택해서 실행한다.

마찬가지로 32비트나 64비트 대응 실행 코드를 유니버셜 바이너리에 포함할 수 있다.

이 기술은 MAB ( Multi-architecture binary) 또는 팻 바이너리(fat binary)라고도 부른다.



-

유비버셜 앱은 하나의 앱 패키지로 다른 여러 환경에 대응해서 동작이 가능한 앱이다.

그러기 위해 번들 안에 각각의 환경을 위한 리소스나 설정 정보를 저장한다.

대부분의 실행 파일은 유니버셜 바이너리이며, 유니버셜 앱이다.



-

어떤 아키텍처 전용의 실행 파일을 작성하려면 컴파일러의 —arch 옵션을 사용한다.

예를 들어 pri.c 라는 소스 파일을 컴파일해서 인텔 32비트 머신용 실행 파일을 만들려면 다음과 같이 하면 된다.

$ clang —arch i386 pri.c



-

iOS 가 동작하는 기기는 ARM 아키텍처 CPU를 사용한다.

컴파일할 때 지정하는 아키텍처는 armv6 또는 armv7 으로 아이폰에서도 아이패드에서도 동작하는 유니버셜 앱을 작성할 때는 armv6 와 armv7 을 동시에 지정한다. ( armv6 뿐이라도 호환성이 있으므로 동작은 한다. )




16.2. nib 파일 로드


* 16.2.1. nib 파일 인스턴스화


-

nib 파일은 GUI 부품 사이의 접속이나 전달되는 메시지를 정의한다.

그 중에는 반드시 소유자라고 불리는 객체가 하나 존재한다.

mediator 라는 객체가 그 역할을 담당한다.

소유자는 그 nib 파일 안의 객체들과 외부 세계를 잇는 중간 다리의 역할이다.




* 16.2.2. Mac OS X 와 nib 파일 로드


-

생략



* 16.2.3. iOS 와 nib 파일 로드


-

-(NSArray*) loadNibNamed: (NSString*)name owner: (id)owner options: (NSDictionary*)options

     문자열로 지정한 이름의 nib 파일(확장자는 불필요)을 번들 안에서 찾아 객체 owner 를 소유자로 한 객체를 인스턴스화한다. 인수 options 에는 옵션 지정이 가능하며 보통은 nil 을 넘긴다. nib 파일 안에서 다른 객체의 부품이 아닌 객체(최상위 레벨의 객체)가 저장된 배열을 돌려준다.



-

iOS 는 nib 파일 안의 모든(소유자 이외) 객체를 참조 카운터 값을 1로 해서 인스턴스화한다.



-

객체 아울렛 설정에는 키-값 코딩 setValue:forKey: 메서드가 사용된다.




* 16.2.4. nib 파일 안의 유지 순환


-

메모리 관리로 ARC 를 사용할 때 nib 파일 안에서도 객체 사이의 유지 순환이 발생하지 않도록 주의해야 한다.



-

커스텀 객체가 지닌 아울렛은 원칙적으로 약한 참조를 사용하도록 항상 주의해야 한다.




* 16.2.5. nib 파일 안의 객체 초기화


-

- (void) awakeFromNib

     nib 파일에서 읽은 다음 인스턴스화, 아울렛 및 액션 접속이 모두 끝나면 호출된다.




* 16.2.6. 앱 실행


-

앱이 가장 먼저 읽어들이는 nib 파일에는 메뉴를 비롯해 실행을 시작하는 데 중요한 요소의 정보가 저장되어 있다.

이것을 메인 nib 파일이라고 부르며 정보 파일에도 파일명이 적혀 있다.

이 파일은 앱 실행 직후, 실행 반복을 시작하기 전에 읽어들인다.



-

메인 nib 파일의 로드 및 실행 반복을 수행하는 건 Mac OS X 에서는 NSApplication, iOS 에서는 UIApplication 이라는 클래스이다.


이 인스턴스는 앱 실행 직후 오직 하나만 생성되어 실행 반복 등 앱의 각종 리소스를 관리한다.

메뉴나 윈도우 관리, 앱 가리기(숨김)나 종료도 이 인스턴스가 한다.






16.3. iOS 파일 저장 장소


* 16.3.1. 주요 디렉터리와 역할


-

iOS 는 보안 문제로 앱 간 파일 교환 등이 제한된다.

따라서 PC 환경과 달리 파일을 저장하는 장소도 앱마다 할당된 특정 장소로 한정된다.

이 장소는 앱이 설치될 때 정해지며 앱 홈 디렉터리라고 부른다.

앱 패키지 및 작성된 파일은 홈 디렉터리 아래에 저장되어 앱이 필요 없어지면 일괄 삭제된다.



-

홈/앱이름.app/

     앱 번들이 있는 위치이다. 서명되어 있으므로 변경하면 안 된다.


홈/Documents/

     앱이 파일을 작성해서 저장하는 장소이다.

     아이튠즈와 연결될 때 백업된다.

     또한 정보 파일의 키 UIFileSharingEnabled 가 YES 이면 아이튠즈를 통해 PC 와 파일을 동기화 할 수도 있다.


홈/Library/Preferences/

     앱 설정이 출력되고, 아이튠즈와 연결할 때 백업된다.


홈/Library/Cached/

     앱이 일시적으로 사용하는 정보를 파일로 저장할 수 있다.

     조작 이력이나 중간 경과 같은 다음 실행 시에 이용할 수 있는 정보를 담는다.

     하지만 디바이스 복원 등을 할 때 삭제되기도 한다.

     아이튠즈에서 백업하지 않는다.


홈/tmp/

     앱이 일시적으로 사용하는 정보로 파일을 저장할 수 있다.

     앱이 동작하지 않을 경우 시스템이 삭제하기도 한다.




* 16.3.2. 디렉터리 경로 취득


-

Documents 와 Caches 경로는 아래 Foundation 프레임워크 함수를 이용하는 것이 바람직한다.


NSArray* NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)


NSSearchPathDirectory 는 NSDocumentDirectory 혹은 NSCachesDirectory 를 사용한다.

NSSearchPathDomainMask 는 NSUserDomainMask

expandTilde 는 YES



-

tmp 디렉터리 경로는 다음 함수로 취득한다.


NSString* NSTemporaryDirectory(void)



-

이런 함수로 취득한 디렉터리 경로가 반드시 있는 것은 아니므로 필요에 따라서는 프로그램에서 생성해야만 한다.

경로가 있는지 확인하거나 디렉터리를 생성하려면 NSFileManager 클래스를 사용한다.




16.4. 사용자 기본값


* 16.4.1. 설정값 저장


-

사용자 기본값(user defaults) 또는 기본 데이터베이스는 NSUserDefaults 클래스를 이용한다.



-

Mac OS X 는 ~/Library/Preferences/ 디렉터리 안에 저장되고, 사용자 기본값이 출력된 파일명은 앱 식별명에 확장자 plist 가 붙는다.


iOS 는 앱 홈 디렉터리의 Library/Preferences/ 디렉터리 안에 저장된다.



-

iOS 는 앱에서 설정값을 변경할 수도 있지만 시스템 도구의 “설정” 메뉴에서 설정하도록 앱을 구축할 수도 있다.

그러려면 Settings 패널을 앱에 도입해야 한다.




* 16.4.2. 기본값 도메인


-

사용자 기본값은 몇 가지 그룹으로 나누어 생각할 수 있다.

그 그룹을 도메인 또는 기본값 도메인(defaults domain)이라고 부른다.

도메인에는 그 내용이 파일에 저장되어 있어 그 후에도 계속 사용하는 것과 앱이 실행 중일 때만 사용할 수 있는 것이 있다.



** 앱 도메인 ( 앱 세팅, persistent )


-

프로퍼티 리스트로 관리되는 앱 고유의 설정값 집합이다.

이 설정값 집합을 앱 도메인이라고 부른다.

도메인 명으로 앱 식별명(identifier)를 사용한다.




** 글로벌 도메인 ( 시스템 세팅, persistent )


-

사용자가 계정을 설정해 각 앱에서 공유하여 사용하는 설정값이다.

예를 들어 사용하는 언어나 파일명 표시에 확장자를 붙일 것인가, 몇 포인트보다 큰 문자를 부드럽게 표시할 것인가 등 다양하다.

도메인명은 NSGlobalDomain 이다.



-

이 도메인은 iOS 에서도 유효해서 설정된 언어나 키보드 정보를 취득할 수 있다.




** 인수 도메인 ( volatile )


-

Mac OS X 의 경우 앱 실행 시 인수를 넘길 수 있는데, 이 녀석이 인수 도메인




** 언어 도메인 ( volatile )


-

사용하는 언어가 지정되어 있을 때 그 언어의 이름 (예를 들어 ko)을 도메인명으로 하는 임시 도메인을 구성한다.

임시 도메인은 파일에 저장되지 않는다.




** 등록 도메인 ( volatile )


-

사용자가 앱의 각종 설정값을 아직 설정하지 않았을 때 사용하는, 미리 정해진 값의 집합이다.

도메인명은 NSRegistrationDomain 으로 파일에 저장되지 않는다.



-

NSUserDefaults 를 사용해 키에서 대응하는 설정값을 찾는데, 그 때 다섯 개의 도메인을 다음 순서대로 탐색해서 최초로 찾은 값을 이용한다.


1. 인수 도메인

2. 앱 도메인 ( 파일에 저장 )

3. 글로벌 도메인 ( 파일에 저장 )

4. 언어 도메인

5. 등록 도메인




* 16.4.3. 사용자 기본값을 조사하는 도구


-

Mac OS X 에서 사용자 기본값은 각 앱에서 조작하는 것 외에도 프로퍼티 리스트 파일을 직접 편집하거나 명령어 줄 도구인 defaults 를 사용해서 접근할 수 있다.

$ defaults read 도메인명


$ defaults read 도메인명 키



-

read 대신 write 나 delete 를 지정하면 값을 덮어쓰거나 삭제할 수 있는데 사용자 기본값을 잘못 다루면 앱이 정상적으로 실행되지 않는 문제가 발생할 수 있으므로 주의해야 한다.




* 16.4.4. NSUserDefaults 개요


-

글로벌 도메인, 인수 도메인, 등록 도메인의 도메인명 문자열은 NSGlobalDomain, NSArgumentDomain, NSRegistrationDomain 변수로 준비되어 있다.



-

-(void) registerDefaults: (NSDictionary*) dictionary

     등록 도메인에 초기값을 추가한다.



-

- (NSDictionary*) dictionaryRepresentation

     모든 도메인 내용을 사전 객체로 취득한다.



-

- (BOOL) synchronize

     도메인 내용에 대응하는 프로퍼티 리스트 파일에 출력한다.

     보통은 이 메서드를 자동 호출하므로 앱이 종료될 때 등 파일에 확실하게 반영하고 싶을 때 이외에는 호출할 필요가 없다.

     어떤 이유로 파일 출력에 실패하면 NO 를 돌려준다.




16.5. 앱의 지역화


* 16.5.1. 메시지 지역화


-

Localizable.strings 파일을 만들어서 각 언어에 대응하는 디렉터리 (언어.lproj) 에 저장해야 한다.

파일명을 다른 이름으로 할 수도 있지만 따로 지정하지 않으면 Localizable.strings 가 사용된다.



-

Localizable.strings 파일은 키가 되는 문자열과 대응하는 값의 문자열 짝을 등호 기호로 묶어 끝에 세미콜론을 붙인 항목의 배열이다.

키도 값도 늘 “ “ 로 둘러싼다.

값은 생략할 수도 있는데, 이 때는 등호도 삭제한다.

값이 생략되면 키 자체가 그 항목의 값이 된다.

또한 주석을 /* … */ 형식으로 기입할 수 있다.



-

파일은 UTF-16 으로 인코딩되어야 한다.



-

-(NSString*) localizedStringForkey:(NSString*)key value:(NSString*)value table:(NSString*)tableName

     인수 tableName 으로 지정한 이름과 확장자 .strings 를 가진 파일을 번들 안에서 찾아 인수 key 로 지정한 키에 대응하는 값의 문자열을 돌려준다.

     인수 value 에는 대응하는 키를 찾을 수 없을 때 반환할 값을 지정한다.

     tableName 이 nil 또는 @“” 이면 Localizable.strings 가 사용된다.



-

지역화된 문자열을 더 간단히 얻기 위한 위의 메서드를 사용한 매크로는 아래와 같다.


NSLocalizedString(key, comment)

NSLocalizedStringFromTable(key, tbl, comment)



-

소스 파일 안에 적혀 있는 이런 매크로에서 Localizable.strings 를 생성하는 명령어 genstrings 가 있다.

명령어 줄에서 인수 없이 genstrings 라고 입력하면 사용법이 표시된다.




* 16.5.2. 지역화 지침


-

앱 명 지역화하기


정보 파일(info.plist) 안에서는 앱명을 원본 앱 번들의 이름으로 작성한다.

이 때 CFBundleDisplayName 과 CFBundleName 이라는 키를 작성한다.


그런 다음 각 언어용 서브 디렉터리에 InfoPlist.strings 파일을 작성한다.


그리고 그 안에 아래와 같이 기입해준다.


CFBundleDisplayName = “앱 이름”;

CFBundleName = “앱 이름”;


CFBundleDisplaayName 문자열은 파인더에 표시가 되고, CFBundleName 은 앱을 실행할 때 메뉴바에 표시되는 16문자보다 짧은 ( 한글이면 8문자정도 ) 문자열을 지정한다.




* 16.5.3. 로케일


-

NSString 에는 localizedStringWithFormat: 클래스 메서드가 있어 stringWithFormat: 과 비슷하게 서식을 지정해서 문자열을 작성할 수 있다.



-

비슷한 메서드로 다음과 같은 초기자가 있다.


-(id)initWithFormat:(NSString*)format locale:(NSDictionary *)dictionary




-

NSArray, NSDictionary 등은 descriptionWithLocale: 이라는 메서드가 있다.




16.6. 모듈의 동적 로드


-

iOS 에서는 이용할 수 없다.





반응형

댓글