Objective - C Runtime 이 실 행 될 때의 2: 구성원 변수 와 속성

http://southpeak.github.io/blog/2014/10/30/objective-c-runtime-yun-xing-shi-zhi-er-:cheng-yuan-bian-liang-yu-shu-xing/
앞의 글 에서 우 리 는 Runtime 에서 클래스 와 대상 과 관련 된 내용 을 소개 했다. 이 장 에서 부터 우 리 는 세부 적 인 내용 과 관련 된 내용 을 토론 할 것 이다. 주로 클래스 중의 구성원 변수, 속성, 방법, 협의 와 분류의 실현 을 포함한다.
이 장의 주요 내용 은 Runtime 에서 구성원 변수 와 속성 에 대한 처리 에 모 입 니 다.토론 하기 전에 우 리 는 먼저 중요 한 개념 인 유형 코드 를 소개 한다.
유형 인 코딩 (유형 인 코딩)
런 타임 에 대한 보충 으로 컴 파일 러 는 모든 방법의 반환 값 과 매개 변수 형식 을 문자열 로 인 코딩 하고 방법의 selector 와 연결 합 니 다.이러한 인 코딩 방안 은 다른 상황 에서 도 매우 유용 하기 때문에 우 리 는 @ encode 컴 파일 러 명령 을 사용 하여 그것 을 얻 을 수 있 습 니 다.형식 을 지정 할 때 @ encode 는 이 형식의 문자열 인 코딩 을 되 돌려 줍 니 다.이러한 유형 은 int, 포인터 와 같은 기본 유형 일 수도 있 고 구조 체, 클래스 등 유형 일 수도 있다.사실 sizeof () 로 작 동 할 수 있 는 매개 변수 유형 은 @ encode () 에 사용 할 수 있 습 니 다.
Objective - C Runtime Programming Guide 의 Type Encoding 1 절 에 Objective - C 의 모든 유형 인 코딩 이 나열 되 어 있 습 니 다.주의해 야 할 것 은 이 유형 들 은 우리 가 압축 파일 과 배포 에 사용 하 는 인 코딩 유형 과 같 습 니 다.압축 파일 에 사용 할 수 없 는 경우 도 있 습 니 다.
주: Objective - C 는 long double 형식 을 지원 하지 않 습 니 다. @encode (long double) 는 d 를 되 돌려 줍 니 다. double 과 같 습 니 다.
하나의 배열 의 형식 인 코딩 은 괄호 안에 있 습 니 다.배열 요소 의 개수 와 요소 유형 을 포함 합 니 다.다음 예제 와 같다.
float a[] = {1.0, 2.0, 3.0};
1
NSLog(@"array encoding type: %s", @encode(typeof(a)));

출력 은:
2014-10-28 11:44:54.731 RuntimeTest[942:50791] array encoding type: [3f]

다른 유형 은 Type Encoding 을 참고 할 수 있 습 니 다. 여기 서 자세히 말 하지 않 습 니 다.
또한 일부 인 코딩 형식 도 있 습 니 다. @ encode 는 직접 되 돌아 오지 않 지만 프로 토 콜 에서 설명 하 는 방법의 유형 한정 문자 로 사용 할 수 있 습 니 다.Type Encoding 을 참고 할 수 있 습 니 다.
속성 에 있어 서 일부 특수 한 유형 인 코딩 도 있 습 니 다. 속성 은 읽 기, 복사, retain 등 임 을 나타 내 고 자세 한 내용 은 Property Type String 을 참고 할 수 있 습 니 다.
구성원 변수, 속성
Runtime 에서 구성원 변수 와 속성 에 관 한 데이터 구 조 는 많 지 않 고 세 개 만 있 으 며 모두 간단 합 니 다.그러나 매우 실 용적 이지 만 자주 무시 되 는 특성 도 있다. 즉, 관련 대상 은 이 소절 에서 상세 하 게 토론 할 것 이다.
기본 데이터 형식
Ivar
Ivar 는 인 스 턴 스 변 수 를 나타 내 는 유형 으로 실제 적 으로 obsc 를 가리 키 고 있 습 니 다.ivar 구조 체 의 지침 은 다음 과 같다.
typedef struct objc_ivar *Ivar;

struct objc_ivar {

    char *ivar_name                 OBJC2_UNAVAILABLE;  //    

    char *ivar_type                 OBJC2_UNAVAILABLE;  //     

    int ivar_offset                 OBJC2_UNAVAILABLE;  //        

#ifdef __LP64__

    int space                       OBJC2_UNAVAILABLE;

#endif

} 

objc_property_t
objc_property_t 는 Objective - C 성명 의 속성 을 나타 내 는 유형 으로 실제 objectproperty 구조 체 의 지침 은 다음 과 같다.
typedef struct objc_property *objc_property_t;

objc_property_attribute_t
objc_property_attribute_t 속성 특성 (attribute) 을 정의 합 니 다. 구조 체 입 니 다. 다음 과 같이 정의 합 니 다.
typedef struct {

    const char *name;           //    

    const char *value;          //    

} objc_property_attribute_t;

관련 개체 (연 결 된 개체)
관련 대상 은 런 타임 에서 매우 실 용적 인 특성 이지 만 무시 되 기 쉽다.
관련 대상 은 구성원 변수 와 유사 하지만 실행 할 때 추 가 됩 니 다.저 희 는 보통 구성원 변수 (Ivar) 를 클래스 성명 의 헤더 파일 에 두 거나 클래스 가 실 현 된 @ implementation 뒤에 두 습 니 다.그러나 분류 에 멤버 변 수 를 추가 할 수 없다 는 단점 이 있다.만약 우리 가 분류 에 새로운 구성원 변 수 를 추가 하려 고 시도 한다 면 컴 파일 러 는 잘못 보고 할 것 이다.
우 리 는 전체 변 수 를 사용 하여 이 문 제 를 해결 하 기 를 바 랄 수도 있다.그러나 이것 은 모두 Ivar 가 아니다. 왜냐하면 그들 은 단독 인 스 턴 스 에 연결 되 지 않 기 때문이다.그래서 이런 방법 은 거의 사용 되 지 않 는 다.
Objective - C 는 이 문제 에 대해 관련 대상 (Associated Object) 이라는 해결 방안 을 제공 했다.
우 리 는 관련 대상 을 Objective - C 대상 (예 를 들 어 사전) 이 라 고 상상 할 수 있 습 니 다. 이 대상 은 주어진 key 를 통 해 클래스 의 인 스 턴 스 에 연 결 됩 니 다.그러나 C 인 터 페 이 스 를 사용 하기 때문에 key 는 void 포인터 (const void *) 입 니 다.런 타임 이 대상 의 메모 리 를 어떻게 관리 하 는 지 알려 주 는 메모리 관리 정책 도 지정 해 야 합 니 다.이 메모리 관리 정책 은 다음 값 으로 지정 할 수 있 습 니 다.
OBJC_ASSOCIATION_ASSIGN

OBJC_ASSOCIATION_RETAIN_NONATOMIC

OBJC_ASSOCIATION_COPY_NONATOMIC

OBJC_ASSOCIATION_RETAIN

OBJC_ASSOCIATION_COPY

숙주 대상 이 풀 려 날 때 지정 한 메모리 관리 정책 에 따라 관련 대상 을 처리 합 니 다.지정 한 정책 이 assign 이면 숙주 가 풀 려 날 때 관련 대상 이 풀 려 나 지 않 습 니 다.retain 이나 copy 를 지정 하면 숙주 가 풀 려 날 때 관련 대상 이 풀 려 납 니 다.우 리 는 심지어 자동 retain / copy 인지 아 닌 지 를 선택 할 수 있다.우리 가 여러 스 레 드 에서 관련 대상 에 접근 하 는 다 중 스 레 드 코드 를 처리 해 야 할 때, 이것 은 매우 유용 하 다.
우리 가 한 대상 을 다른 대상 에 연결 하 는 데 필요 한 것 은 바로 아래 두 줄 의 코드 이다.
static char myKey;

objc_setAssociatedObject(self, &myKey, anObject, OBJC_ASSOCIATION_RETAIN);

이 경우 self 대상 은 새로운 관련 대상 anObject 를 가 져 옵 니 다. 메모리 관리 전략 은 자동 retain 관련 대상 입 니 다. self 대상 이 풀 릴 때 자동 으로 release 관련 대상 을 가 져 옵 니 다.또한, 우리 가 같은 key 를 사용 하여 다른 대상 을 연결 할 때 도 이전 관련 대상 을 자동 으로 방출 합 니 다. 이 경우 이전 관련 대상 은 잘 처리 되 고 새로운 대상 은 메모 리 를 사용 합 니 다.
id anObject = objc_getAssociatedObject(self, &myKey);

우 리 는 obbc 를 사용 할 수 있다.removeAssociated Objects 함 수 를 사용 하여 관련 대상 을 제거 하거나 obsc 를 사용 합 니 다.setAssociated Object 함 수 는 key 가 지정 한 관련 대상 을 nil 로 설정 합 니 다.
관련 대상 의 사용 방법 을 실례 를 들 어 보 여 드 리 겠 습 니 다.
Tap 제스처 동작 을 모든 UIView 에 동적 으로 연결 하고 필요 에 따라 클릭 한 실제 동작 을 지정 하려 고 한다 고 가정 합 니 다.이때 우 리 는 제스처 대상 과 작 동 하 는 block 대상 을 우리 의 UIView 대상 에 연결 할 수 있다.이 임 무 는 두 부분 으로 나 뉜 다.우선, 필요 하 다 면 제스처 인식 대상 을 만 들 고 블록 과 관련 된 대상 으로 해 야 합 니 다.다음 코드 와 같이:
- (void)setTapActionWithBlock:(void (^)(void))block

{

    UITapGestureRecognizer *gesture = objc_getAssociatedObject(self, &kDTActionHandlerTapGestureKey);



    if (!gesture)

    {

        gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(__handleActionForTapGesture:)];

        [self addGestureRecognizer:gesture];

        objc_setAssociatedObject(self, &kDTActionHandlerTapGestureKey, gesture, OBJC_ASSOCIATION_RETAIN);

    }



    objc_setAssociatedObject(self, &kDTActionHandlerTapBlockKey, block, OBJC_ASSOCIATION_COPY);

}

이 코드 는 제스처 인식 과 관련 된 대상 을 감지 했다.없 으 면 관련 관 계 를 만 들 고 만 듭 니 다.동시에 들 어 오 는 블록 대상 을 지정 한 key 에 연결 합 니 다.block 대상 의 관련 메모리 관리 정책 에 주의 하 십시오.
제스처 인식 대상 은 target 과 action 이 필요 하기 때문에 다음 에 처리 방법 을 정의 합 니 다.
- (void)__handleActionForTapGesture:(UITapGestureRecognizer *)gesture

{

    if (gesture.state == UIGestureRecognizerStateRecognized)

    {

        void(^action)(void) = objc_getAssociatedObject(self, &kDTActionHandlerTapBlockKey);



        if (action)

        {

            action();

        }

    }

}

우 리 는 제스처 인식 대상 의 상 태 를 검사 해 야 한다. 왜냐하면 우 리 는 클릭 제스처 가 인식 되 었 을 때 만 조작 을 수행 해 야 하기 때문이다.
위의 예 에서 우 리 는 관련 대상 이 사용 하기에 복잡 하지 않다 는 것 을 알 수 있다.그것 은 우리 로 하여 금 기 존의 기능 을 동태 적 으로 강화 할 수 있 게 한다.우 리 는 실제 인 코딩 에서 이 특성 을 유연 하 게 운용 할 수 있다.
구성원 변수, 속성의 조작 방법
구성원 변수
구성원 변수 작업 은 다음 과 같은 함 수 를 포함 합 니 다.
//        

const char * ivar_getName ( Ivar v );



//           

const char * ivar_getTypeEncoding ( Ivar v );



//           

ptrdiff_t ivar_getOffset ( Ivar v );

● ivar_getOffset 함수, 형식 id 또는 다른 대상 유형의 인 스 턴 스 변 수 는 object 를 호출 할 수 있 습 니 다.getIvar 와 objectsetIvar 는 구성원 변 수 를 직접 방문 하고 오프셋 을 사용 하지 않 습 니 다.
관련 대상
관련 대상 조작 함 수 는 다음 과 같다.
//       

void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy );



//       

id objc_getAssociatedObject ( id object, const void *key );



//       

void objc_removeAssociatedObjects ( id object );

관련 대상 및 관련 인 스 턴 스 는 이미 앞에서 토론 하 였 으 며, 여기에서 더 이상 중복 되 지 않 습 니 다.
속성
속성 조작 관련 함 수 는 다음 과 같 습 니 다.
//      

const char * property_getName ( objc_property_t property );



//            

const char * property_getAttributes ( objc_property_t property );



//           

char * property_copyAttributeValue ( objc_property_t property, const char *attributeName );



//          

objc_property_attribute_t * property_copyAttributeList ( objc_property_t property, unsigned int *outCount );

● property_copy AttributeValue 함수, 되 돌아 오 는 char * 사용 후 free () 를 호출 하여 풀 어야 합 니 다.
● property_copy AttributeList 함수, 반환 값 은 사용 후 free () 를 호출 하여 풀 어야 합 니 다.
실례
이러한 장면 을 가정 하면 우 리 는 서버 의 두 개의 서로 다른 인터페이스 에서 같은 사전 데 이 터 를 얻 을 수 있 지만 이 두 인 터 페 이 스 는 두 사람 이 쓴 것 이 고 같은 정 보 는 서로 다른 필드 로 표시 된다.우 리 는 데 이 터 를 받 을 때 이 데 이 터 를 같은 대상 에 저장 할 수 있다.대상 클래스 는 다음 과 같 습 니 다.
@interface MyObject: NSObject



@property (nonatomic, copy) NSString    *   name;                  

@property (nonatomic, copy) NSString    *   status;                 



@end

인터페이스 A, B 가 되 돌아 오 는 사전 데 이 터 는 다음 과 같다.
@{@"name1": "  ", @"status1": @"start"}



@{@"name2": "  ", @"status2": @"end"}

일반적인 방법 은 두 가지 방법 을 써 서 각각 전환 하 는 것 이다. 그러나 Runtime 을 유연 하 게 활용 할 수 있다 면 하나의 전환 방법 만 실현 할 수 있다. 이 를 위해 우 리 는 먼저 맵 사전 (전역 변수) 을 정의 해 야 한다.
static NSMutableDictionary *map = nil;



@implementation MyObject



+ (void)load

{

    map = [NSMutableDictionary dictionary];



    map[@"name1"]                = @"name";

    map[@"status1"]              = @"status";

    map[@"name2"]                = @"name";

    map[@"status2"]              = @"status";

}



@end

위의 코드 는 두 사전 의 서로 다른 필드 를 MyObject 의 같은 속성 에 비 추어 다음 과 같이 처리 할 수 있 습 니 다.
- (void)setDataWithDic:(NSDictionary *)dic

{

    [dic enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {



        NSString *propertyKey = [self propertyForKey:key];



        if (propertyKey)

        {

            objc_property_t property = class_getProperty([self class], [propertyKey UTF8String]);



            // TODO:            

            NSString *attributeString = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];



            ...



            [self setValue:obj forKey:propertyKey];

        }

    }];

}

물론 하나의 속성 이 위 와 같은 방식 으로 처 리 될 수 있 는 전 제 는 KVC 를 지원 하 는 것 이다.
작은 매듭
이 장 에서 우 리 는 Runtime 에서 구성원 변수 와 속성 과 관련 된 내용 을 토론 했다.구성원 변수 와 속성 은 클래스 의 데이터 기반 으로 Runtime 의 관련 조작 을 합 리 적 으로 사용 하면 우 리 는 클래스 데이터 와 관련 된 업 무 를 더욱 유연 하 게 처리 할 수 있다.
레 퍼 런 스
Objective-C Runtime Programming Guide
Associated Objects

좋은 웹페이지 즐겨찾기