Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Objective-C에서 private 메서드 사용하기

Objective-C에는 다른언어들처럼 메서드에 대해서 접근제어를 하는 public/private같은 예약어가 존재하지 않기 때문에 실제로 private 메서드가 존재하지 않습니다.(Objective-C를 잘 모르지만 @private는 인스턴스 변수에만 사용가능한 것으로 알고 있습니다. 여기저기 찾아봤는데 왜 Objective-C에는 Private Methods가 없는가에 대한 얘기는 이 글의 답변이 제일 나은것 같습니다.) 다만 .h파일의 인터페이스에 메서드의 시그니처를 명시해서 외부에서 보이도록 할 수 있습니다. 하지만 클래스내에서는 외부에 노출할 필요는 없지만 클래스 내부에서만 사용하기위한 private 메서드가 필요합니다.


// PackagesViewController.h
#import <UIKit/UIKit.h>

@interface PackagesViewController : UITableViewController {
   NSMutableArray *packages;
}

@end


// PackagesViewController.m
#import "PackagesViewController.h"

@implementation PackagesViewController

- (void)viewDidLoad {
   [super viewDidLoad];

   [self findGroup:packages];
}

- (void)findGroup:(NSMutableArray *)array {
}
@end

예를 들어 위와같이 private 메서드목적으로 findGroup메서드를 정의할 수 있고 이 메서드는 .h파일에는 명시하지 않았고 위에서 [self findGroup]와 같은 형태로 호출을 합니다.

하지만 여기에 문제가 있는데 컴파일러가 private 메서드의 여부를 알지 못한다는 것입니다. 컴파일러는 .h파일에 정의된 선언만 확인하기 때문입니다. 때문에 @implementation부분에서 private 메서드를 호출할 경우 해당 메서드는 .h파일에 정의가 안되어있으므로 아래 화면처런 findGroup가 없다는 경고메시지를 보여줍니다. 물론 실제로는 동작하기 때문에 실행을 하면 findGroup가 정상적으로 호출이 됩니다.(컴파일러가 메서드의 존재여부에 대한 정보를 가질 수 없었을 뿐입니다.) 하지만 개발자로써 의도한 정상적인 코드에 경고메시지가 나타나는 것은 상당히 신경쓰이는 일입니다.

사용자 삽입 이미지

이 문제를  카테고리 기능을 사용해서 해결할 수 있습니다.


// PackagesViewController.m
#import "PackagesViewController.h"

@interface PackagesViewController(Private)
- (void)findGroup:(NSMutableArray *)array;
@end


@implementation PackagesViewController

- (void)viewDidLoad {
   [super viewDidLoad];

   [self findGroup:packages];
}
@end

@implementation PackagesViewController (Private)
- (void)findGroup:(NSMutableArray *)array {
}
@end

위와 같이 카테고리 기능을 이용해서 Private라는 이름의(다른 이름도 됩니다.) 카테고리를 만들고 이 카테고리를 구현한 @implementation을 정의해서 이곳에 메서드를 구현해 주면 됩니다. 이렇게 구현하면 컴파일러 경고 없이 private method를 사용할 수 있습니다. 구현부를 따로 나누고 싶지 않다면 이름이 없는 카테고리 기능을 사용해서 해결할 수 있습니다. 이 이름이 없는 카테고리 기능을 class continuation이라고 부른다고 합니다.

// PackagesViewController.m
#import "PackagesViewController.h"

@interface PackagesViewController()
- (void)findGroup:(NSMutableArray *)array;
@end


@implementation PackagesViewController

- (void)viewDidLoad {
   [super viewDidLoad];

   [self findGroup:packages];
}


- (void)findGroup:(NSMutableArray *)array {

}

@end

이렇게 작성해도 동일하게 동작하며 2가지 방법 모두 카테고리에 정의한 메서드를 구현하지 않으면 컴파일러 경고가 뜨기 때문에 실수도 방지할 수 있습니다.(컴파일 오류는 나지 않습니다.)

사용자 삽입 이미지

2가지 방법 중 작성이 좀 더 편리한 class continuation쪽이 낫지 않나 생각하고 있습니다. 저도 공부중이라 위에서 언급한 부분외의 차이점외에는 아직 잘 모르겠습니다. A Quick Objective-C 2.0 Tutorial: Part II에서는 카테고리를 사용했을때의 컴파일러 경고에 대해서 언급하고 그 대안으로 class continuation에 대해서 언급하고 있지만 이리 저리 테스트해봤는데(아직 초심자라 디테일한 테스트라하기는 어렵지만) 딱히 언급된 문제는 찾을 수 없었습니다.
2011/05/12 01:56 2011/05/12 01:56