Objective - C 는 연합 저장 소 를 통 해 클래스 증가 속성 및 원리 분석

7974 단어 Objective-C
공동 저장 실현 방식 및 바 텀 원리 분석
저자: wangzz
원문 주소: http://blog.csdn.net/wzzvictory_tjsd/article/details/9347981
전재 출처 를 밝 혀 주 십시오
동적 언어의 가장 큰 장점 은 바로 유연성 이다. Objective - C 에 있어 운영 할 때 동적 으로 유형 을 증가 하 는 방법 과 인 스 턴 스 변 수 는 많은 다른 언어 들 이 부러워 하 는 능력 이다.인 스 턴 스 변 수 를 추가 하 는 데 사용 되 는 기술: 공동 저장.
1. 공동 저장 의 실현 방식
다음 코드 는 Duck 클래스 에 color 속성 을 증가 시 킵 니 다:
Duck + associative. h 파일
#import "Duck.h"

@interface Duck (associative)

@property (nonatomic, retain) NSString *color;

@end
Duck + associative. m 파일
#import "Duck+associative.h"
#import <objc/runtime.h>

@implementation Duck (associative)

static char colorKey = NULL;

- (NSString *)color {
    return objc_getAssociatedObject(self, &colorKey);
}

- (void)setColor:(NSString *)aColor {
    objc_setAssociatedObject(self, &colorKey,
                             aColor,
                             OBJC_ASSOCIATION_RETAIN);
}

호출 예:
Duck    *smallDuck = [[Duck alloc] init];
smallDuck.color = @"red color";
NSLog(@"duck color:%@",smallDuck.color);
[smallDuck release];

출력 결과:
2013-07-18 19:09:26.578 ObjcRunTime[429:403] duck color:red color

이로써 우 리 는 Duck 류 에 color 속성 을 추가 하 는 데 성공 했다.
2. 유형 동태 적 으로 속성 을 증가 하 는 데 사용 되 는 기술
주로 세 가지 디자인 모델 을 사용 했다.
1. 접근 기 (accessor)
접근 기 모드 는 Cocoa 디자인 모델 에서 매우 중요 한 것 으로 소량의 방법 (보통 get 과 set 방법) 을 통 해 방문 질문 류 의 모든 인 스 턴 스 를 참조 하 는 것 이 목적 입 니 다.이 기술 을 통 해 Duck 류 는 color 인 스 턴 스 변수 가 없 지만 공동 저장 을 통 해 인 스 턴 스 변수 와 똑 같은 효 과 를 실현 할 수 있 습 니 다.이런 것들 은 유형의 사용자 에 게 실현 디 테 일 을 차단 했다.
접근 기 모드 는 공동 저장 소 를 통 해 속성 을 증가 시 키 는 필수 전제 라 고 할 수 있다.
2. 카 테 고리 (카 테 고리)
카 테 고리 가 실 행 될 때 클래스 동적 인 증가 방법 을 사용 할 수 있 습 니 다. 이것 은 방문 기 모드 를 이용 하여 클래스 속성 을 증가 시 킬 수 있 는 기반 입 니 다.
3. 공동 저장 (associative storage)
카 테 고리 와 접근 기 를 통 해 공동 저장 기술 을 결합 하여 우 리 는 클래스 에 속성 을 추가 하 는 기능 을 완성 했다.이 모든 것 은 사용자 로 하여 금 정말 새로운 인 스 턴 스 변 수 를 증가 시 킨 것 처럼 느끼 게 하지만, 실제로 우 리 는 방문 기 를 통 해 하 나 를 시 뮬 레이 션 했 을 뿐, 진정 으로 증가 한 것 이 아니다.
3. 공동 저장 의 실현 원리
위의 예 를 통 해 알 수 있 듯 이 클래스 의 속성 을 증가 시 키 는 것 은 so easy 로 보 이 는 일 로 주로 obbc 를 바 꾸 었 습 니 다.setAssociated Object 와 obbcgetAssociated Object 두 가지 방법.나의 의문 은 클래스 가 증가 하 는 속성 에 대응 하 는 대상 값 을 어디 에 저장 하 였 습 니까?다음은 이 두 가지 방법의 실현 부분 을 통 해 답 을 찾 아 보 자.
1、objc_setAssociated Object 방법의 실현 부분:
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy) {
    if (UseGC) {
        //              ,     
        if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
            value = objc_msgSend(value, @selector(copy));
        }
        auto_zone_set_associative_ref(gc_zone, object, key, value);
    } else {
        //             
        // Note, creates a retained reference in non-GC.
        _object_set_associative_reference(object, key, value, policy);
    }
}

상술 한 방법 에서 알 수 있 듯 이
objc_setAssociated Object 가 실제로 호출 한 것 은:
2、_object_set_associative_reference 방법의 실현 부분:
__private_extern__ void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    uintptr_t old_policy = 0;
    // NOTE:  old_policy is always assigned to when old_value is non-nil.
    id new_value = value ? acquireValue(value, policy) : nil, old_value = nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        if (new_value) {
            //  new_value   ,    associations   map,  object               ObjectAssociationMap  
            // break any existing association.
            AssociationsHashMap::iterator i = associations.find(object);
            if (i != associations.end()) {
                //object   associations   map     ObjectAssociationMap  refs
                //  refs     key   value
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    //    key  value,   value policy       
                    ObjcAssociation &old_entry = j->second;
                    old_policy = old_entry.policy;
                    old_value = old_entry.value;
                    old_entry.policy = policy;
                    old_entry.value = new_value;
                } else {
                    //      key  value, value policy   key   map 
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                }
            } else {
                // object   associations   map      ObjectAssociationMap  
                //      ObjectAssociationMap  ,  new_value  key       map   
                // create the new association (first time).
                ObjectAssociationMap *refs = new ObjectAssociationMap;
                associations[object] = refs;
                (*refs)[key] = ObjcAssociation(policy, new_value);
                _class_assertInstancesHaveAssociatedObjects(object->isa);//  object  ,        
            }
        } else {
            //new_value  ,      key   value,      key   value 
            // setting the association to nil breaks the association.
            AssociationsHashMap::iterator i = associations.find(object);
            if (i != associations.end()) {
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    ObjcAssociation &old_entry = j->second;
                    old_policy = old_entry.policy;
                    old_value = (id) old_entry.value;
                    refs->erase(j);
                }
            }
        }
    }
    // release the old value (outside of the lock).
    if (old_value) releaseValue(old_value, old_policy);
}
3. 이 방법의 실현 부분 을 통 해 알 수 있 듯 이 runtime 시스템 에서:

하나의 사례 가 있 는 Associations HashMap 인 스 턴 스
이 실례 의 생 성 방식 은 다음 과 같다.
AssociationsHashMap &associations() {
        if (_map == NULL)
            _map = new(::_malloc_internal(sizeof(AssociationsHashMap))) AssociationsHashMap();
        return *_map;
    }

② Associations HashMap 인 스 턴 스 는 Object Association Map 대상 을 저장 하 는 데 사 용 됩 니 다.
③ 각 클래스 는 하나의 Object Association Map 인 스 턴 스 를 가지 고 있 으 며, 각 클래스 는 공동 저장 모드 를 통 해 저 장 된 키 쌍 도 Object Association Map 인 스 턴 스 에 저 장 됩 니 다.
④ Key 에 대응 하 는 값 은 상 관 없 이 key 의 주소 가 필요 합 니 다. 따라서 key 를 정의 할 때 보통 쓰 는 방법 은 다음 과 같 습 니 다.
static char colorKey = NULL;

즉, 어떤 데 이 터 는 사실 Associations HashMap 인 스 턴 스 에 저 장 된 것 이다.
지금 은 모든 것 이 갑자기 밝 아 지 는 것 같다!
4. 공동 저장 의 장단 점
1. 장점
공동 저장 의 가장 큰 장점 은 유연 한 방식 으로 속성 을 증가 시 킬 수 있다 는 것 이다.
2. 단점
효율 이 낮다.
단일 기계 명령 을 사용 하면 실제 인 스 턴 스 변 수 를 방문 할 수 있 지만 맵 에 저 장 된 값 을 방문 하려 면 여러 함수 호출 이 필요 하 며 효율 문 제 는 주의해 야 합 니 다.
사실 현재 많은 코코아 류 는 NSAttributedString, NSFileManager, NSNotification, NSProcessInfo 등 이 연합 저장 소 를 광범 위 하 게 사용 하고 있다.

좋은 웹페이지 즐겨찾기