본문 바로가기

iOS개발팁

싱글턴을 활용한 카테고리 연관저장

ObjectiveC의 강력한 점 중 하나는 카테고리 기능입니다. 기존 클래스에 새로운 기능을 갖는 메서드를 아주 쉽게 추가할 수 있죠.

하지만 카테고리의 아쉬운 점은 인스턴스변수를 새로 만들 수 없다는 점입니다. 하지만 해결책은 있는 법 바로 맥개발자들이 즐겨쓰는 연과저장 기법입니다. 간단하게 static 형식으로 전역 변수 성격을 갖는 NSDictionary, NSArray와 같은 컨테이너 변수 사용하여 카테고리 메서드 내에서 사용하는 것입니다.

하지만 아이폰은 메모리가 한정되어 있기 때문에 메모리경고를 받을 경우 메모리 정리를 해주어야 합니다. 단지 static으로만 변수를 선언하여 사용하면 자신 스스로 메모리 관리를 할 수 없다는 단점이 있습니다.

이럴 때 싱글턴 기법을 사용하여 카테고리에서 사용하는 연관데이터싱글턴을 만들고 이 싱글턴객체가 메모리경고 통지를 듣고 처리할 수 있도록 해 주면 문제는 해결 됩니다. 물론 싱글턴패턴도 내부적으로 static변수를 사용하지만 차이점은 자체적으로 메소드를 가질 수 있다는 점이고 메모리 경고나 기타 통지에 대해서 능동적으로 대처할 수 있는 장점이 있습니다.

아래는 테스트 코드로 UIView에 카테고리 메서드를 넣고 연관데이터를 저장하는 객체를 싱글턴으로 만든 코드입니다.

//UIView+Helper.h
#import <UIKit/UIKit.h>

@interface UIView(Helper)
-(void)addViewName:(NSString *)viewName;
-(NSString *)viewName:(NSString *)key;
@end

//UIView+Helper.m
#import "UIView+Helper.h"
#import "SynthesizeSingleton.h"

@interface UIViewPrivateStore : NSObject
{
    NSMutableDictionary *data;
}
+(UIViewPrivateStore *)sharedInstance;
@property(nonatomic, retain) NSMutableDictionary *data;
@end

@implementation UIViewPrivateStore
@synthesize data;
SYNTHESIZE_SINGLETON_FOR_CLASS(UIViewPrivateStore);
-(id)init
{
    self = [super init];
    if(self!=nil)
    {
        self.data = [NSMutableDictionary dictionary];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(receivedMemoryWarning:)
                                                     name:UIApplicationDidReceiveMemoryWarningNotification
                                                   object:nil];
    }
    return self;
}
-(void)receivedMemoryWarning:(NSNotification *)noti
{
    NSLog(@"receivedMemoryWarning");
    [self.data removeAllObjects];
}
-(void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIApplicationDidReceiveMemoryWarningNotification
                                                  object:nil];
    self.data = nil;
    [super dealloc];
}
@end



@implementation UIView(Helper)
-(void)addViewName:(NSString *)viewName
{
    NSMutableDictionary *data = [[UIViewPrivateStore sharedInstance] data];
    [data setObject:viewName forKey:viewName];
}
-(NSString *)viewName:(NSString *)key
{
    NSMutableDictionary *data = [[UIViewPrivateStore sharedInstance] data];
    return [data objectForKey:key];
}
@end

위의 코드 중 싱글턴을 생성해 주는 SYNTHESIZE_SINGLETON_FOR_CLASS 매크로 내용은 "싱글턴을 활용하자" 글을 참고하시길 바랍니다.

위의 코드를 실행하고 메모리경고를 시뮬레이트하면 UIViewPrivateStore의 메모리경고에 대한 통지 핸들러가 호출되어 싱글턴객체 스스로가 내부 메모리를 정리하는 코드를 실행합니다.

전체 예제를 첨부합니다. 해피코딩하세요!