DirTy™의 하루일과/DirTy™의 가당찮은iOS

[IOS] 객체에 객체를 추가해보자! Associated Objects

DirTy™ 2015. 12. 15. 10:06

iOS4 및 Mac OS X 10.6(snow leopard)부터 지원되기 시작한 Associated Objects.

널리 알려져 있지않지만 상당히 유용하게 사용할 수 있는 것 같다.


쉽게 설명해 보면 UIButton을 눌렀을때 파라미터를 전달하고 싶을때 간단하게 NSDictionary등의

파라미터를 같이 UIButton에 추가할 수 있다.


사용하기전에 일단 아래에 정의되어 있으니 import.

#import <objc/runtime.h>


사용은 아래의 메서드를 사용하면 된다.

objc_getAssociatedObject  /  objc_setAssociatedObject /  objc_removeAssociatedObjects

 

objc_setAssociatedObject 에서 사용되는 AssociationPolicy의 종류는 아래와 같다.

enum {

OBJC_ASSOCIATION_ASSIGN = 0, // 추가된 객체와 약한 참조
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 추가된 객체와 강력 참조 및 nonatomatic으로 설정
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, // 추가된 객체를 복사 및 nonatomatic으로 설정
OBJC_ASSOCIATION_RETAIN = 01401, // 추가된 객체와 강력 참조 및 atomatic으로 설정
OBJC_ASSOCIATION_COPY = 01403 // 추가된 객체를 복사 및 atomatic으로 설정

}; typedef uintptr_t objc_AssociationPolicy;

 

객체가 추가될 때 사용된 policy가 copy나 retain인 경우는 객체가 제거될 때 해당 객체의 메모리가 release 된다.

여러 개의 객체들 중 하나만 제거하고 싶으면 해당 객체를 추가할때 사용한 key를 이용해 nil를 추가하면 된다.

Associated Objects를 이용해 copy나 retain policy로 추가된 객체들은

(objc_setAssociatedObject의 object로 넘긴) 대상 객체의 dealloc이 실행될 때 모두 release 된다.

 

NSObject의 subclass이기만 하다면 어떤 class의 instance에도 Associated Objects를 이용해서 객체를 추가할 수 있기 때문에

특히 UIView 의 instance 같은 UI component들에 데이터를 추가할 때 유용하다.

특정 객체에 NSDictionary 형식의 데이터 guide 를 추가하고자 한다면 다음과 같이 할 수 있다.

 

- (NSObject *)getProperty:(NSObject *)obj {

    return objc_getAssociatedObject(obj, @"guide");

}


- (void)setProperty:(NSObject *)obj value:(NSObject *)value {

    objc_setAssociatedObject(obj, @"guide", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

- (void)removeProperty:(NSObject *)obj {

    objc_removeAssociatedObjects(obj);

}

 

또, UIAlertView의 click액션에 대해 아래와 같이 간단하게 block구문을 추가하여 처리할수도 있다.


static void *MyAlertViewKey = "MyAlertViewKey";

- (void)OnlogOut {

    DLog(@"%s", __PRETTY_FUNCTION__);

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"로그아웃"

                                                    message:@"정말로 로그아웃 할거냐?"

                                                   delegate:self

                                          cancelButtonTitle:@"싫타고!"

                                          otherButtonTitles:@"하라고!", nil];

   

    void (^block)(NSInteger) = ^(NSInteger buttonIndex) {

        if (buttonIndex == 0) {

            DLog(@"LOGOUT CANCEL");

        } else {

            DLog(@"LOGOUT OK");

        }

    };

   

    objc_setAssociatedObject(alert, MyAlertViewKey, block, OBJC_ASSOCIATION_COPY);

    [alert show];

}


// UIAlertViewDelegate protocol method

- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {

    void (^block)(NSInteger) = objc_getAssociatedObject(alertView, MyAlertViewKey);

    block(buttonIndex);

}


위와같이 어떤 객체에 대해 유연하게 대처 가능한 Associated Objects 를 활용해 보자.