[iOS] Associated References – 클래스 수정없이 임의 객체 저장

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

Leave a comment

Leave a comment