Associated Reference는 객체 인스턴스 변수를 기존 클래스에 추가할 때 사용한다.
이를 사용하면 객체 저장소를 위한 클래스 수정없이 – 클래스 재정의 없이 -, 임의의 객체(연관 객체)를 클래스(소스 객체)에 추가하고 필요할 때 사용할 수 있다.
Association은 key 기반으로 동작한다. 서로 다른 키로 여러가지 연관 객체를 소스 객체에 등록할 수 있다. Association Reference는 소스 객체의 라이프 사이클 내에 연관 객체의 사용을 보장한다. 즉, 소스 객체가 해제되면 소스 객체에 추가된 연관 객체도 해제된다.
Associated Reference를 사용하려면 <objc/runtime.h>가 필요하다.
예제를 통해 알아보자. 아무런 프로퍼티가 없는 SourceClass 객체에 NSString 타입의 임의 객체를 저장하고 획득함을 보여준다 (Xcode 내장 단위 테스트 프레임웍 OCUnit을 이용하였다. 테스트 코드 구조는 신경쓸 필요 없다.)
#import <objc/runtime.h> // 1. 아무런 프로퍼티가 없는 소스 클래스 정의 @interface SourceClass @end // 테스트 클래스 정의, OCUnit 사용 @interface AssociatedReferenceTests :SenTestCase @end // 2. key 정의 static const char *assoicatedReferenceTestKey = "AssociatedReferenceTestKey"; @implementation AssociatedReferenceTests{ SourceClass *sourceObject; } -(void)setUp{ sourceObject = [[SourceClass alloc]init]; } -(void)tearDown{ sourceObject = nil; } -(void)testAssoicatedReferenceSimpleTest{ // 3. sourceObject에 추가할 임의 객체 NSString* addedObject = @"AddedObject"; // 4. addedObject를 sourceObject에 저장. // sourceObject에는 NSString 타입의 프로퍼티가 없음 objc_setAssociatedObject( sourceObject, // 객체를 저장할 소스 객체 assoicatedReferenceTestKey, // 키 addedObject, // 저장할 객체 OBJC_ASSOCIATION_RETAIN); // Association policy addedObject = nil; // 5. sourceObject로부터 키 값으로 저장된 객체 반환. nil이면 안됨 STAssertNotNil(objc_getAssociatedObject(sourceObject, assoicatedReferenceTestKey), @"Associated Reference should get a object"); // 정확한 확인을 위해 받아오면 "AddedObject" 가 할당됨 addedObject = (NSString*)objc_getAssociatedObject(sourceObject, assoicatedReferenceTestKey); } // sourceObject의 라이프사이클이 끝나면 연관객체도 받아올 수 없음 -(void)testAssoicatedObejectIsNotValidWhenSourceObjectIsNil{ NSString* addedObject = @"AddedObject"; objc_setAssociatedObject( sourceObject, assoicatedReferenceTestKey, addedObject, OBJC_ASSOCIATION_RETAIN); sourceObject = nil; STAssertNil(objc_getAssociatedObject(sourceObject, assoicatedReferenceTestKey), @"Associated object is not valid if source object is deallocatd"); } @end
객체 저장 메소드와 획득 메소드는 각각 아래와 같다.
- void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy),
- id objc_getAssociatedObject(id object, const void *key)
연관 객체와 소스 객체 사이의 관계를 끊으려면 저장 메소드 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) 의 id value 인자에 nil을 넣어준다. 이 때 소스 객체와 끊으려는 키는 정확한 값을 넣는다.
void objc_removeAssociatedObjects(id object) 메소드는 소스 객체의 모든 Associated Reference를 해제한다. 모든 관계를 끊기 때문에 다른 코드에 영향을 미칠 수 있으므로 사용에 주의해야 한다.
*Reference : iOS Developer Library – Associated References