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

[Objective-C] 기타

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

 [Objective-C] 기타


출처 : OS X 구조를 이해하면서 배우는 Objective-C 부록

addressbook, apple prefix reserve, application, arc, autorelease, C, cf, CFAllocatorRef, cfarray, CFArrayAppendArray, CFArrayCallBacks, CFArrayContainsValue, CFArrayCreate, CFArrayGetCount, CFArrayRef, CFBridgingRelease, CFBridgingRetain, CFData, CFDictionary, CFDictionaryRef, CFGetRetainCount, CFGetTypeID, CFIndex, cfmutablearray, CFRelease, cfretain, CFShow, cfstr, cfstring, CFStringCreateWithFormat, CFStringRef, CFType, CFTypeRef, CGRectCGRectUnion, cgrectcontainspoint, CGRectContainsRect, CGRectGetHeight, CGRectGetMaxX, CGRectGetMidX, CGRectGetWidth, CGRectUnion, convention, core foundation, corefoundation, coregraphics, CoreVideo, C언어, derive, description, Did, Foundation 프레임워크 개요, Free, Get, ID, is형, k prefix, kCFTypeArrayCallBacks, malloc, name convention, nscountedset, NSIndexSet, NSLocking, NSMutableIndexSet, NSMutableOrderedSet, nsobject, NSOrderedSet, NSProcessInfo, NSString, Objective-C, opaque type, openFile:withApplication:andDeactivate, QuickTime, should, stderr, toll-free bridged, UIKit, will, [Objective-C] 기타, __bridge, __bridge_retained, __bridge_retained, __bridge_transfer, 객체 사용자화, 단어 조합 규칙, 명명 규칙, 명명규칙, 불투명형, 상수형, 소유권 정책, 애플 접두사 예악어, 애플 접두사 예약, 접두어, 주요 클래스 개요, 챀조 카운터 방식, 카테고리를 포함한 파일명, 클래스명과 프로토콜명, 톨프리 객체의 형변환, 톨프리 브릿지, 파생, 패키지명

A. Foundation 프레임워크 개요


* A.1 주요 클래스 개요


-

NSCountedSet : 변경 가능한 집합의 클래스, 같은 객체를 여러 번 포함할 수 있다.

NSOrderedSet, NSMutableOrderedSet : 여러 객체를 배열처럼 순서대로 저장하는데 같은 객체는 하나만 저장

NSIndexSet, NSMutableIndexSet : 배열의 인덱스로 사용하는 음수가 아닌 정수를 요소로 하는 집합. NSSet 과 상속 관계가 없다.



-

NSProcessInfo : 프로세스에 관련된 다양한 정보를 취득한다.




* A.2. 주요 프로토콜 개요



* A.3. 주요 함수와 형식


-

CGRectGetHeight(CGRect rect)

CGRectGetWidth(CGRect rect)

CGRectGetMaxX(CGRect rect)

...


CGRectGetMidX(CGRect rect)

...

CGRectContainsRect(CGRect aRect, CGRect bRect)

CGRectContainsPoint(CGRect rect, CGPoint point)

CGRectCGRectUnion(CGRect r1, CGRect r2)

...




B. Core Foundation 프레임워크 개요


* B.1. Core Foundation 이란


-

Core Foundation 프레임워크란 기본적으로 Cocoa Foundation 프레임워크를 기반으로 기본 데이터 조작 기능을 C 언어로 다시 작성한 것.

Core Foundation 에서 사용할 수 있는 자료형은 배열이나 집합 등의 컬렉션, 문자열, 바이트 배열, 날짜와 시각, URL 같은 Foundation 프레임워크와 공통인 것이 많다.



-

iOS 에서 QuickTime 이나 CoreGraphics, CoreVideo, AddressBook 같은 다양한 프레임워크에서 CoreFoundation 을 기본 자료형으로 이용한다.

Foundation 과 Application 또는 UIKit 프레임워크만으로 작성할 수 있는 앱이라면 일부러 Core Foundation 을 사용할 필요가 없다.



-

Core Foundation 의 기본은 C 언어이며 Objective-C 의 Foundation 프레임워크와 개념적으로는 공통된 부분이 많지만 유닉스 표준 라이브러리와 비교하면 꽤 복잡하다.




* B.2. 자료형과 형식명


-

Core Foundation 은 C 로 작성되었는데 데이터와 함수의 캡슐화를 구현하기 위해 그 자료형은 ‘객체’라고 부른다.

하지만 클래스에 해당하는 것은 없다.

기존 자료형을 상속해서 서브 클래스에 해당하는 자료형을 작성하는 기능도 없다.



-

Foundation 프레임워크와 같이 문자열, 배열, 사전 등의 자료형이 있어서 접두사 ‘CF’를 붙여 CFString, CFArray, CFDictionary 가 된다.

하지만 이것을 프로그램 안에서 형식명으로 사용하지 않는다.

문자열 객체를 다룰 때 프로그램에서는 CFStringRef 를 사용하고, 배열은 CFArrayRef, 사전은 CFDictionaryRef 를 사용한다.

CFStringRef 형은 문자열 객체의 실체를 가리키는 포인터이므로 NSString 으로 생각하면 NSString* 형에 해당한다.



-

Core Foundation 자료형의 실체는 구조체이지만 내부는 은폐되어 있어서 직접 조작할 수 없다.

제공되는 건 데이터를 조작하는 함수뿐이다.

이것을 Core Foundation 객체는 불투명형(opaque type)이라고 부르는 이유다.

opaque 는 안이 보이지 않는다는 의미이다.




* B.3. Foundation 객체와의 호환성


-

Core Foundation 객체는 Objective-C 의 Foundation 의 몇몇 클래스 인스턴스와 동등하게 취급할 수 있다.

런타임 시스템이 실제 데이터 구조로부터 어떤 객체인지 판단해서 적절히 처리하므로 서로 데이터 변환을 하지 않아도 된다.

이것을 ‘toll-free bridged(톨프리)’라고 부른다.



-

톨프리 관계에 있는 것은 캐스트를 해야 하지만 서로 변수에 대입하거나 메서드 인수나 반환값으로 사용할 수 있다.



-

톨프리 관계에 있는 것은 CFString과 NSString, CFArray 와 NSArray 등 주요 자료형이나 컬렉션을 포함해 많은 종류가 있다.

톨프리 관계에 있다면 레퍼런스에 적혀 있으며, Foundation 의 이런 클래스는 클래스 클러스터에도 있다.



-

톨프리 이외에도 Core Foundation 객체와 Foundation 프레임워크 객체는 몇몇 장면에서 동등하게 다룰 수 있다.




* B.4. CFType 과 파생 자료형


-

Core Foundation 에는 객체지향의 상속 기능이 없지만 Core Foundation 의 모든 객체를 총칭하는 자료형으로 CFType 이 있다.

프로그램 안에서 형식명으로 CFTypeRef 를 사용한다.

총칭이란 어떤 객체 대신 사용할 수 있다는 의미로, NSObject 또는 id 형의 관계와 비슷하다.



-

Objective-C 의 프로퍼티 리스트에 해당하는 CFPropertyList 자료형이 있는데, 이 자료형은 CFData, CFString, CFArray, CFDictionary, CFDate, CFBoolean, CFNumber 중 하나라는 걸 뜻한다.



-

CFMutableArray 는 CFArray 에서 파생(derive)한다고 표현한다.

객체지향의 상속 기능처럼 보이며 프로그램도 그렇게 생각하며 작성할 수 있다.

그러나 객체지향 언어의 상속 관계가 있는 것도 아니고 프로그래머가 새로운 서브 클래스에 해당하는 것을 만들 수 있는 것도 아니다.

어디까지나 Core Foundation 안에서만 자료형 사이에 상속과 비슷한 관계가 있다는 것 뿐이다.



-

객체가 실제로는 어떤 형식인지 알아보려면 다음 함수를 사용한다.


CFTypeID CFGetTypeID(CFTyperRef cf)


반환값 CFTypeID 는 부호 없는 정수로(uint), Core Foundation 의 각 자료형마다 값이 정해져 있다.

CFArray 에 해당하는 CFTypeID 값은 CFArrayGetTypeID() 함수로 알 수 있으므로 변수 obj 에 저장된 객체가 CFArray 인지는 다음과 같은 if 문으로 판단할 수 있다.

다른 자료형도 마찬가지로 CF___GetTypeID() 함수가 있다.

if (CFGetTypeID(obj) == CFArrayGetTypeID()){

     // ...

}




* B.5. 명명규칙


-

Core Foundation 은 함수나 매크로명 앞에 대상이 되는 자료형을 밝히는 것이 원칙이다.

따라서 Objective-C 의 메서드명이나 매크로명과는 어순이 달라진다.


예를 들어


CFArrayAppendArray()

CFArrayGetCount()

CFArrayContainsValue()


Core Foundation 객체 전체, 즉 CFTypeRef 형을 대상으로 할 때나 자료형과 관계없을 때는 접두사 ‘CF’만 붙인다.



-

상수형은 첫머리에 소문자 ‘k’ 가 붙는다.




* B.6. 객체 생성과 메모리 관리


-

Core Foundation 객체는 동적으로 생성되는데 메모리 관리는 참조 카운터 방식을 사용한다.

Objective-C 와 같은 소유권 정책이 있다.



-

객체를 생성하는 함수로 새로운 객체를 만드는 것과 이미 존재하는 객체의 복사본을 만드는 것이 있다.

새로운 객체 생성은 Create, 복사는 Copy 를 함수명에 포함한다.

이런 함수를 호출해서 반환값으로 받은 객체에는 소유권이 발생한다.

반대로 반환값이 객체의 함수로 소유권의 전달이 발생하지 않을 때는 Get 같은 단어를 사용한다.



-

소유권 관련하여 아래 함수들이 있다.

CFRetain

CFRelease

CFGetRetainCount : 이 함수는 디버그용이며, 실제 프로그램에서 사용하면 안 된다.



-

Core Foundation 에는 CFArray 같은 컬렉션 객체가 있으므로 여기에 객체를 추가하거나 삭제할 때 Foundation 과 마찬가지로 참조 카운터의 증가와 감소가 발생한다.



-

앱이 수동 카운터 관리 방식으로 동작할 때 Core Foundation 객체는 Foundation 의 retain, release 메시지를 이용할 수도 있고, autorelease 메시지를 사용해서 자동 해제 풀을 이용 할 수도 있다.

하지만 id 형으로 캐스트해야 한다.


ex)

CFStringRef str = ...

[(id)str autorelease];

CFArrayAppendValue(arr, str);






* B.7. ARC 와 톨프리 객체의 형변환


-

ARC 를 사용할 때 컴파일러가 소유권 판단을 해서 retain 이나 release 에 해당하는 코드를 보충해주는 건 Objective-C 객체와 관련된 부분뿐이다.

Core Foundation 객체에 대해서는 아무것도 하지 않는다.

Core Foundation 쪽의 소유권 관리는 지금까지 해온 것처럼 수동으로 해야 한다.



-

ARC 는 Core Foundation 쪽 상황을 파악하지 않으므로 프로그래머가 적절하게 조절해서 소유권 관리에 모순이 생기지 않도록 해야 한다.



-

톨프리 관계에 있는 객체를 참조 카운터의 영향을 전혀 의식하지 않고 형변환하려면 다음처럼 캐스트한다.

CFDateRef cfdate = CFDateCreate(NULL, tm);

NSDate* d = (__bridge NSDate*)cfdate;


NSDate *nsdate = [[NSDate alloc] init];

CFDateRef e = (__bridge CFDateRef)nsdate;



-

위의 코드에서 위쪽 캐스팅은 강한 참조 변수에 대입하므로 참조 카운터를 하나 늘리도록 ARC 가 코드를 집어 넣어 카운터값이 2가 된다.

하지만 ARC 를 관리하는 것은 대입으로 늘어난 +1 뿐이므로 이대로는 객체가 해제되지 않는다.

이 대입 후 Core Foundation 쪽에서는 소유권을 관리하지 않고 ARC 쪽에 맡긴다고 하면 Core Foundation 쪽의 소유권을 파기해야 한다.

CFRelease() 를 사용할 수도 있지만 캐스트를 다음처럼 바꿔 쓰는 방법이 있다.

NSDate* d = (__bridge_transfer NSDate*)cfdate;


캐스트로 __bridge_transfer 를 지정하면 식 평가나 대입이 끝난 후 ARC 가 객체의 참조 카운터를 하나 줄인다.

결국 카운터값은 변화하지 않고 소유권은 Core Foundation 쪽에서 ARC 쪽으로 이동한 것처럼 보이게 된다.

이 캐스트에서 결과 형식은 Objective-C 객체여야만 한다.



-

위의 코드에서 아래쪽 캐스팅은 변수 nsdate 의 동작과 관련 없이 Core Foundation 쪽에서 객체를 계속 사용하려면 참조 카운터값을 하나 늘려둬야 한다.

CFRetain() 을 사용하는 방법도 있지만 다음처럼 캐스트를 작서할 수도 있다.

CFDateRef e = (__bridge_retained CFDateRef)nsdate;


이 캐스트에서 ARC 가 참조 카운터를 하나 늘린다.



-

정리하면, Core Foundation 쪽에서 생성한 객체를 ARC 쪽에 전달하려면 __bridge_transfer 를 지정한 캐스트를 사용하고 반대로 ARC 가 관리하는 객체를 Core Foundation 쪽에 전달하려면 __bridge_retained 를 사용한다.

참조 카운터에 변경이 없는 변수에는 __bridge 를 사용한다.



-

__bridge_retained, __bridge_transfer 를 캐스트로 사용하는 대신 인라인 함수를 사용할 수도 있다.

CFTypeRef CFBridgingRetain(id x);

id CFBridgingRelease(CFTypeRef X);




* B.8. 객체 사용자화


-

Core Foundation 자료형에는 상속 같은 구조는 없지만 객체를 생성할 때 그 객체가 어떻게 동작할지 사용자화할 수는 있다.

CFArray 객체를 생성하는 함수 CFArrayCreate() 를 보면..


CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks)


allocator 는 메모리 획득, 해제를 하기 위한 객체이다.

NULL 을 넘기면 미리 정해진 방법으로 메모리 관리를 하지만 다른 방법으로 malloc/free 를 사용해서 지정할 수도 있다.


values 와 numValues 는 배열 요소와 개수이다.


callBacks 는 구조체 포인터로, 미리 준비해둥 구조체 데이터에 있는 kCFTypeArrayCallBacks 포인터를 전달하면 미리 정해진 방법이 채용된다.

이 구조체를 직접 준비할 수 있다.

구조체는 몇몇 함수 포인터를 포함하며 요소가 추가될 때의 유지 동작, 요소가 삭제될 때의 해제 동작을 담당하는 함수 등을 지정할 수 있다.

이것을 이용해서 유지도 해제도 하지 않는 배열이나 유지 대신 복사본을 만드는 배열을 작성할 수도 있다.




* B.9. 편리한 문자열 기능


-

Core Foundation 문자열형 CFString 은 프로그램 안에 문자열 상수로 작성할 때 CFSTR() 매크로를 사용한다.

이 매크로의 인수로는 C 언어 문자열 상수만 사용하며, 아스키 코드 문자 이외의 문자를 사용하면 동작을 보증할 수 없다.



-

함수 CFStringCreateWithFormat() 은 printf 함수와 같은 서식 문자열을 사용해서 CFString 문자열을 생성하는데 서식 문자열도 CFString 이어야 한다.



-

서식 문자열에는 %@ 를 포함할 수 있다.

이 서식에 대응하는 인수가 Objective-C 객체일 때는 description 메서드가 적용된 결과의 문자열이 삽입된다.



-

CFType 으로 정의된 디버그용 함수로 CFShow() 가 있다.

이 함수는 객체를 인수로 그 내용을 나타내는 문자열을 에러 출력(stderr) 에 출력한다.




* B.10. 다른 프레임워크와의 관계



* B.11. CoreFoundation 자료형




C. 코딩 지침


* C.1. 지침이 필요한 이유



* C.2. 단어 조합 규칙



* C.2. 접두어


-

밑줄(언더스코어, _ ) 로 시작하는 이름을 접두어로 사용해선 안 된다.

밑줄로 시작하는 이름은 애플 사가 API 를 구성하는 동안에 사용하는 인스턴스 변수나 비공개 메서드명으로 사용한다고 예약되어 있다.




* C.4. 이름에 사용하는 단어


-

간결한 이름이 좋다고 해도 단어를 줄이는 건 피해야 한다.

코드를 작성한 사람은 줄임말이란 걸 감지할 수 있어도 배경 지식이 없는 사람이 보면 달라지기 때문이다.

널리 사용되고 역사가 오래된 줄임말은 허용한다고 코딩 가이드라인에 명시한다.

매개변수명이나 임시 변수명에는 생략형을 써도 된다.



-

같은 의미의 단어가 몇 가지 있을 때는 Cocoa API 와 같은 단어를 사용한다.



-

전치사 사용법도 초기화할 때 파라미터를 지정하는 with, 위치를 표시하는 at, 출력 방향을 나타내는 to 등 전형적인 예가 몇 가지 있으므로 Cocoa API 가 어떻게 하는지 따라하면 된다.


복수형 사용법도 주의해야 한다.




* C.5. 클래스명과 프로토콜명


-

프로토콜명도 클래스명과 같은 클래스명과 혼돈할 때가 많으므로 프로토콜명에는 ‘~ing’ 를 붙여서 구별하기도 한다.

클래스명 NSLock 과 NSLocking 이라는 프로토콜 명이 그 예이다.




* C.6. 카테고리를 포함한 파일명


-

카테고리의 인터페이스와 구현 부분을 파일로 만들 때 <클래스명+카테고리명.m> 같이 파일명을 붙이는 것이 표준처럼 되어 있다.

NSString+Utils.m 이 그 예이다.




* C.7. 메서드명 관련 일반 규칙


-

getter 에 보통 ‘get’ 은 붙이지 않는다.

get 이 메서드명에 있다면 대부분 포인터가 가리키는 장소에 있는 값을 복사해서 반환한다는 것을 뜻한다.

예를 들어 NSDate 의 메서드 bytes 는 데이터의 바이트 배열의 첫머리 포인터를 돌려줄 뿐인데, 다른 메서드 getBytes: 는 인수 포인터가 가리키는 메모리 영역에 데이터를 복사한다.



-

단순 나열하는 인수의 키워드에는 보통 and 를 붙이지 않는다. 나쁜 예이다.

하지만 메서드 구 개가 서로 다른 동작을 한다면 그 둘을 and 로 묶는 것은 괜찮다.


openFile:withApplication:andDeactivate:




* C.8. 접근자 규칙



* C.9. 객체 집합 조작



* C.10. 인수명에 대한 주석



* C.11. 인스턴스 변수명



* C.12. 함수명



* C.13. 형식명, 상수명, 문자열 상수명


-

무엇이 이미 발생한 것을 알리는 이름은 동사 과거형이 아닌 did + 동사원형 으로 하고,

반대로 지금부터 무엇이 일어난다는 것을 알리는 이름에는 will + 동사원형 으로 한다.



-

사전 키로 사용하는 문자열명 끝에는 Key, 비트합으로 마스크를 만드는 상수는 끝에 Mask 를 붙이는 등 명문화되지 않은 관습이 많다.

물론 그런 관습을 반드시 따라야만 하는 것은 아니다.




* C.14. 델리게이트의 메서드명과 알림명


-

'~를 해도 되는가’ 라고 문의하는 메시지가 오기도 하는데 이런 메시지명은 ‘should + 동사 원형’ 을 사용한다.




* C.15. 전역이자 유일한 이름


-

전역인 이름을 하나밖에 없는 것으로 하려면 자바 패키지명을 짓는 것과 같은 명명규칙을 추천한다.


com.company.appName




반응형

댓글