본문 바로가기
아이폰 개발/Objective C

objective c 프로토콜 3 - 비공식 프로토콜

by 인생여희 2020. 12. 31.

objective c 프로토콜 3 - 비공식 프로토콜

 

 

공식 프로토콜은 고유한 이름을 가지며 @protocol [이름]을 가지고 선언된 프로토콜 중 클래스나 카테고리에 채용(상속)된 프로토콜을 뜻한다. 비공식 프로토콜은 NSObject 클래스에 추가된 카테고리 메소드를 뜻한다. 외형적으로 프로토콜 형식을 가지지 않는다.

 

 

이전 포스팅에서 NSObject 에 (Dummy)로 추가된 프로토콜 메소드는 비공식 프로토콜이라고 해야하나? 이 경우에는 프로토콜이다. 왜냐면 <Print> 라는 프로토콜 이름을 가지고 있기 때문이다. 비공식 프로토콜이란 NSObject에 추가된 카테고리 메소드만을 뜻한다. 

 

 

왜 이런 개념을 도입했나?

언제든지 선택적으로 메소드를 정의하거나 정의하지 않아도 되는 여분의 메소드 집합을 표현하기 위해서이다. 비공식 메소드는 구현하지 않아도 경고가 발생하지 않는다. 또한 NSObject에 추가된 카테고리 선언 .h을 임포트하여야 카테고리 메소드의 존재를 알 수 있다. 반대로 이 메소드에 관계없는 다른 모듈은 추가된 메소드 선언에 대해 신경쓸 필요가 없기 때문에 불필요한 영향도 최소화할 수 있다는 장점이 있다. 

 

비공식 프로토콜을 가장 많이 활용하는 부분은 delegate 로 어떤 이벤트가 발생했을 경우 다른 객체가 추가로 처리할 부분을 정의할 때 사용한다. 바로 이러한 부분이 AppKit 과 UIKit을 활용하여 프로그래밍 하는 부분이기도 하다. 즉, 앱의 제작은 delegate의 정의라고도 볼 수 있다. 

 

 

시스템 클래스는 특정 이벤트/메시지가 발생하였을때 처리를 담당한다고 가정한다. 초기에 객체가 생성된 기본 상태에서는 다른 객체를 참조하는 delegate 변수는 nil 값을 가진다. 

 

delegate 변수 값이 nil 인 경우 메소드 -act는 현재 시스템 클래스가 지정한 작업만 수행한다. 그러나 사용자가 -setDelegate: 에 의해 delegate 변수에 객체 id를 배정한 후에 -act 가 동작하면 [delegate additionalAct] 작업을 추가로 수행한다. 즉, 이벤트를 처리하는 객체는 delegate 설정에 따라 작업을 위임하여, 사용자가 원하는 추가작업을 선택적으로 수행할 수 있게 된다. 이러한 선택적 추가작업을 위해 비공식 프로토콜을 미리 선언한다. 

 

참고

 

 

 

 

보편적인 UIKit의 delegate 동작

 

추가 작업을 위한 객체 변수 delegate는 위와 같이 id 형식으로 선언하며 설정과 참조를 위한 기본 메소드를 가진다. 개선된 Objective C 에서는 @property와 @synthesize 구문으로 대신할 수 있다.

 

 

예제 

 

main.m

 

#import <Foundation/Foundation.h>

//비공식 프로토콜 선언
@interface NSObject (MyInformalProtocol)
-(void)processInformal;
@end


//비공식 프로토콜 구현 시작
@interface Delegation : NSObject
-(void)processInformal;
@end

@implementation Delegation
-(void)processInformal
{
	printf("delegation\n");
}
@end
//비공식 프로토콜 구현 끝



@interface Processor : NSObject
//delegate 역할 객체 포인터
@property (assign, readwrite) id delegate;
-(void)process;
@end

@implementation Processor
@synthesize delegate;
-(void)process
{
	printf("process \n");
    
    //델리게이트 객체가 설정되어 있고, 비공식 프로토콜에 응답 가능할 때 ,
    //delegate 업무 위임하여 수행
    if([delegate respondsToSelector:@selector(processInformal)]){
		[delegate processInformal];
    }
}
@end

int main(int argc, const char * argv[])
{
	@autoreleasepool
	{
        
        //프로세스 인스턴스 생성 후 -process 수행
        //delegate의 초기값은 nil 로 processInfomal 이 수행되지 않는다.
		id p = [[Processor alloc] init];
		[p process];
        
        
        //위 인스턴스에 delegate 설정 후 -process 수행.
        //delegate 객체에 추가작업 processInfomal을 수행
		id d = [[Delegation alloc] init];
		[p setDelegate:d];
		[p process];
		
        
        
		[p release];
		[d release];
	}
    return 0;
}

/*
 출력
 
 process : 델리게이트 설정전 기본작업만 수행
 
 
 process : 델리게이트 설정후 기본작업과 추가 작업 실행
 delegation
 Program ended with exit code: 0
 */

 

 

0502-protocol informal.zip
0.09MB

 

 

아래 그림에서 Processor의 인스턴스 p가 처음 process 메소드를 수행할 때는 내부에 delegate 변수 값이 설정되지 않아 nil 상태이다. 이럴 경우 nil 객체로 전달되는 모든 메시지는 무시된다. 이후 객체 p에 delegate 변수를 비공식 프로토콜을 채용하는 클래스 Delegation의 객체 d로 설정하였다.

 

 

 

 

이때 다시 객체 p에 -process 메소드를 발송하면 p의 자체 작업이 완료된 이후, delegate 변수에 저장된 객체가 @selector(processInformal)을 수행할 수 있는지 점검한 후에 메시지를 발송한다. 메시지를 받은 객체 d는 자체적으로 수행할 추가 작업을 수행한다.