Objective - C 소스 코드 (5) Associated Objects 의 실현 원리
Objective - C 에 서 는 Category 를 통 해 기 존의 클래스 에 속성 을 추가 할 수 있 지만 인 스 턴 스 변 수 를 추가 할 수 없다 는 것 을 알 고 있 습 니 다. 이것 은 Objective - C 의 뚜렷 한 단판 이 된 것 같 습 니 다.그러나 다행히도 우 리 는 Associated Objects 를 통 해 이 부족 함 을 보완 할 수 있다.
본 고 를 읽 는 과정 에서 독 자 는 다음 과 같은 세 가지 문제 에 중심 을 두 어야 한다.
Associated Objects 와 관련 된 함 수 는 주로 세 가지 가 있 습 니 다. runtime 소스 코드 의 runtime. h 파일 에서 설명 을 찾 을 수 있 습 니 다.
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
이 세 함수 의 이름 은 쉽게 알 아 볼 수 있다.
주: obj cremoveAssociated Objects 함 수 는 일반적으로 사용 할 수 없습니다. 이 함 수 는 한 대상 의 모든 관련 대상 을 제거 하고 이 대상 을 '원시' 상태 로 복원 하기 때 문 입 니 다.이렇게 하면 다른 사람 이 추가 한 관련 대상 도 함께 제거 할 가능성 이 높다. 이것 은 우리 가 원 하 는 것 이 아니다.그래서 일반적인 방법 은 obbcsetAssociated Object 함수 가 nil 에 들 어 와 기 존 관련 대상 을 제거 합 니 다.
Key 값:
앞의 두 함수 중의 key 값 은 우리 가 중점적으로 주목 해 야 할 점 입 니 다. 이 key 값 은 하나의 대상 등급 (왜 대상 등급 입 니까? 아래 장 을 보면 알 수 있 습 니 다) 의 유일한 상수 입 니 다.일반적으로 다음 과 같은 세 가지 추천 키 값 이 있 습 니 다.
세 번 째 종 류 를 추천 합 니 다. 사용 하기 쉽 고 코드 량 을 절약 합 니 다.
관련 정책
관련 정책 등가 속성 설명 OBJCASSOCIATION_ASSIGN @property (assign) or 약 인용 관련 대상
@property (unsafe_unretained)
OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (strong, nonatomic) 관련 대상 을 강하 게 인용 하고 비원 자 조작
OBJC_ASSOCIATION_COPY_NONATOMIC @property (copy, nonatomic) 관련 대상 을 복사 하고 비원 자 조작
OBJC_ASSOCIATION_RETAIN @property (strong, atomic) 관련 대상 을 강하 게 인용 하고 원자 조작
OBJC_ASSOCIATION_COPY @property (copy, atomic) 관련 대상 복사 및 원자 조작
원자 문 제 는 여기 서 토론 하지 않 고 다음 에 주로 앞의 세 가지 형식 을 토론 한다.
실현 원리
코드 Github 원본 링크:https://github.com/leichunfeng/AssociatedObjects
테스트 코드 에서 알 수 있 듯 이:
obj c - references. mm 를 열 고 obj c 를 찾 습 니 다.setAssociated Object 함수 가 최종 호출 된 함수;
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
if (new_value) {
// break any existing association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// secondary table exists
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
j->second = ObjcAssociation(policy, new_value);
} else {
(*refs)[key] = ObjcAssociation(policy, new_value);
}
} else {
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
} else {
// setting the association to nil breaks the association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
refs->erase(j);
}
}
}
}
// release the old value (outside of the lock).
if (old_association.hasValue()) ReleaseValue()(old_association);
}
obj c - references. mm 의 obj cgetAssociated Object 함수 가 최종 호출 된 함수:
id _object_get_associative_reference(id object, void *key) {
id value = nil;
uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
ObjcAssociation &entry = j->second;
value = entry.value();
policy = entry.policy();
if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);
}
}
}
if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
((id(*)(id, SEL))objc_msgSend)(value, SEL_autorelease);
}
return value;
}
objc_removeAssociatedObjects
이 함 수 는 한 대상 의 모든 관련 대상 을 제거 하고 구체 적 으로 실현 하 는 것 도 대상 의 주소 에 따라 해당 하 는 Object Association Map 대상 을 가 져 온 다음 모든 관련 구 조 를 하나의 vector 에 저장 한 다음 vector 에 저 장 된 모든 관련 대상 을 방출 합 니 다.앞의 실험 에서 관찰 한 상황 에 따 르 면 한 대상 이 풀 려 날 때 도 바로 이 함수 로 모든 관련 대상 을 제거 합 니 다.
클래스 대상 에 관련 대상 추가
소스 코드 를 본 후에 우 리 는 대상 주소 와 Associations HashMap 해시 표 가 일일이 대응 한 다 는 것 을 알 게 되 었 다.그렇다면 우 리 는 이런 문 제 를 생각 할 것 이다. 유형 대상 에 게 관련 대상 을 추가 할 수 있 을 까?답 은 긍정 적 이다.우 리 는 클래스 대상 에 게 똑 같은 방식 으로 관련 대상 을 추가 할 수 있 습 니 다. 그러나 우 리 는 일반적인 상황 에서 이렇게 하지 않 습 니 다. 왜냐하면 우 리 는 static 변 수 를 통 해 클래스 등급 의 변 수 를 실현 할 수 있 기 때 문 입 니 다.나 는 분류 ViewController + Associated Objects 에서 ViewController 클래스 대상 에 관련 대상 associated Object 를 추가 했다. 。
총결산
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.