티스토리 뷰

Key-Value Coding Programming Guide - Key-Value Coding Fundamentals - Representing Non-Object Values

NSObject에 있는 KVC 프로토콜 메소드는 기본적으로  객체와 객체가 아닌 프로퍼티에도 작동합니다.

(여기서 객체가 아닌 프로퍼티는 구조체 와 int, BOOL, char 등 primitive(원시 타입)을 가리킵니다. 이건 또 sacalar값이라고도 부릅니다.) 기본적으로 set할 때 객체 인자값이나 get 할 때 리턴값과 non-object 프로퍼티를 자동으로 변환합니다. 이렇게 하면 key-based getter와 setter가 스칼라 타입이나 구조체에서도 동일하게 작동합니다.


!!! 스위프트에는 모든 프로퍼티가 객체이기 때문에 상관없습니다.


valueForKey: 같은 getter 메소드를 보면 기본적으로 key에 해당하는 값을 리턴하기 위해서 특정 접근자 메소드나 인스턴스변수를 찾습니다. 이 부분은 Accessor Search Patterns에 나와 있습니다. 만약 리턴할 값이 객체 가아니면 ( 스칼라나 구조체이면 ) wrapping 해서 리턴합니다. 스칼라이면 NSNumber로, 구조체이면 NSValue로 래핑합니다. 


위와 비슷하게 setValue:forKey와 같은 setter메소드도 key에 해당하는 프로퍼티에 값을 넣기위해 접근자 메소드나 인스턴스를 찾습니다. 만약 key에 해당하는 프로퍼티가 객체가 아니면 setter메소드는 인자 객체에 적절 <type>Value 보내서 기본값을 뽑아내고 저장합니다. ( setValue:forKey:를 이용해서 넣을 때는 랩핑해서 넣습니다.)


!!! setter메소드를 사용할 때 non-object property에 nil을 넣을 경우 setNilValueForKey:메시지를 호출합니다. 그리고 이 메소드는 기본적으로 NSInvalidArgumentExceptioon 예외를 발생시킵니다. 하지만 이 메소드를 오버라이드 해서 원하는 처리도 할 수 있습니다. Handling Non-Object Value에서 확인할 수 있습니다.



- Wrapping and Unwrapping Scalar Types

아래는 스칼라 타입 목록입니다.  KVC가 wrap이나 unwrap 할때 사용하는 메소드들입니다.

KVC에서 get 할 때 객체가 아닌 값은 Creation method중 하나를 사용해서 NSNumber로 wrap한 다음리턴합니다. 

KVC에서 set 할 때는 객체가 아닌 값은 사용자가 Creation method중 하나를 사용해서 넣어줘야겠죠.

또한 key에 해당하는 프로퍼티가 객체가 아니면 Accessor method중 하나를 적절히 사용해서 기본 값을 꺼내 프로퍼티에 넣어줍니다.


Table 5-1Scalar types as wrapped in NSNumber objects

Data type

Creation method

Accessor method

BOOL

numberWithBool:

boolValue (in iOS)

charValue (in macOS)*

char

numberWithChar:

charValue

double

numberWithDouble:

doubleValue

float

numberWithFloat:

floatValue

int

numberWithInt:

intValue

long

numberWithLong:

longValue

long long

numberWithLongLong:

longLongValue

short

numberWithShort:

shortValue

unsigned char

numberWithUnsignedChar:

unsignedChar

unsigned int

numberWithUnsignedInt:

unsignedInt

unsigned long

numberWithUnsignedLong:

unsignedLong

unsigned long long

numberWithUnsignedLongLong:

unsignedLongLong

unsigned short

numberWithUnsignedShort:

unsignedShor

* mac os에서는 역사적인 이유로(무슨 이유일까요?) BOOL은 typedef signed char입니다. KVC에서는 이 둘을 구별하지 않습니다. 따라서 key가 BOOL 이라고 해서 @"true"나 @"YES"같은 문자열 값을 setValue:forKey:에 전달하면 안됩니다. 만약 보내면 charValue를 호출하게 됩니다.(BOOL을 char이기 때문에) 그러나 NSString에는 그런 메소드가 없기 때문에 런타임에러가 납니다. 따라서 @(1)이나 @(YES)를 NSNumber에 담아서 보내야 합니다. iOS는 해당되지 않습니다. iOS에서는 BOOL은 native Boolean인 bool로 정의돼 있기 때문에 KVC는 boolValue를 호출합니다. 이 메서드는 NSNumber과 NSString 두 객체에 모두 있습니다.



Wrapping and Unwrapping Structures
스칼라타입과 내용은 똑같습니다. 대상이 다를 뿐입니다.
Table 5-2Common struct types as wrapped using NSValue.

Data type

Creation method

Accessor method

NSPoint

valueWithPoint:

pointValue

NSRange

valueWithRange:

rangeValue

NSRect

valueWithRect: (macOS only).

rectValue

NSSize

valueWithSize:

sizeValue

자동 wrapping 과 unwrapping은 위 4가에만 해당되지 않습니다. 스트럭쳐 타입이면 다 해당됩니다. Objective-C type encoding 문자열이 { 로 시작하면 다 해당됩니다. 커스텀 타입을 얘기하는 것 같습니다. 아무튼 이런 타입은 다 NSValue로 래핑됩니다. 아래는 예시입니다.

Listing 5-1A sample class using a custom structure
  1. typedef struct {
  2. float x, y, z;
  3. } ThreeFloats;
  4. @interface MyClass
  5. @property (nonatomic) ThreeFloats threeFloats;
  6. @end
위와 같이 구조체와 클래스가 있다고 했을 때, 아래와 같이 하면 threeFloats getter를 호출해서 값을 NSValue객체로 랩해서 리턴합니다.

NSValue* result = [myClass valueForKey:@"threeFloats"];

위와 비슷하게 아래와 같이하면 기본적으로 NSValue의 getValue함수를 가지고 값을 unwrap하고 그 구조체를 setThreeFloats 함수를 통해 넣습니다.

!주의
KVC에서는 주고 받는 객체는 모두 id타입입니다. (id 타입은 객체를 가리키는 포인터입니다.) 따라서 컴파일 시에 타입검사가 진행되지 않습니다. 이 부분을 주의해야겠습니다. 잘 못하면 의도 하지 않은 객체를 주고 받을 수 있습니다. 또한 모든 스칼라 타입 NSNumber로 랩핑되고, 모든 구조체가 NSValue로 랩핑되느 것도 불안합니다.



반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함