본문 바로가기
ios 뽀개기/objective-c

protocol 개념 - 1

by 인생여희 2019. 10. 9.
반응형

objective c 에서 프로토콜이라는 문법이 있다. 프로토콜은 약속,규칙이라는 뜻이다. 예를들어, Car Class 에 '작동' 이라는 프로토콜(약속)이 존재 한다면, 이 약속을 airplain, bike 등 여러 클래스에서 가져다가 사용할 수 있다. 조금 어렵게 말하면 프로토콜은 인터페이스(선언부) 이고, delegate 는 인터페이스를 구현하는 객체이다. 그럼 프로토콜을 쓰면 좋은점은 무엇일까? 바로 객체간 종속성이 줄어든다! 

//프로토콜 선언!
@protocol ProtocolName <ProtocolToExtend>
@optional
//구현해도 되고 안해도 되는 메소드
@required
//필수적으로 구현해야 하는 메소드
@end


//프로토콜 구현!
@interface ClassName : 부모클래스 <ProtocolName> 

or

@interface ClassName () <ProtocolName>

 

시나리오)
나는 강아지를 기른다. 강아지는 배고플때 나를 쳐다 보고, 나가고 싶을때는 wow라고 짓는다. 그럴때 나는 강아지에게 먹을것을 주거나, 밖으로 데리고 나간다. 이것을 소스로 구현해 보자.

//나.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@class MyDog;
@interface Me : NSObject

//강아지가 나를 기대하며 쳐다본다.
-(void) myDogDidLookHopeful:(MyDog *) mydog;

//강아지가 나에게 와우라고 짓는다.
-(void) myDogSayWow:(MyDog *) mydog;
@end

NS_ASSUME_NONNULL_END

//나.m

#import "Me.h"

@implementation Me
//강아지가 나를 기대하며 쳐다본다.
-(void) myDogDidLookHopeful:(MyDog *) mydog{
    NSLog(@"좋아, 밥줄게~ 밥먹자~~");
}


//강아지가 나에게 와우라고 짓는다.
-(void) myDogSayWow:(MyDog *) mydog{
    NSLog(@"좋아, 나가서 놀자~!");
}
@end

 

//강아지.h

#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN


@class Me;  //나

@interface MyDog : NSObject

@property (nonatomic, strong) Me *taker;    //돌봐주는 사람

- (void) wantToGoOut;                       //나가 놀고 싶다.
- (void) isHungry;                          //배고프다

@end
NS_ASSUME_NONNULL_END

//강아지.m

#import "MyDog.h"
#import "Me.h"


@implementation MyDog

//나가고 싶어할때
- (void) wantToGoOut{
    
   [_taker myDogSayWow:self];		//돌봐주는 사람에게 와우라고 소리친다.
}

//배고플때
- (void) isHungry{
     [_taker myDogDidLookHopeful:self];	//돌봐주는 사람을 쳐다본다.
    
}
@end

//실행.viewController.m

#import "ViewController.h"

#import "Me.h"
#import "MyDog.h"
#import "Jack.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    
    MyDog *mydog = [[MyDog alloc]init];     //강아지
    Me *me = [[Me alloc]init];              //나
    Jack *jack = [[Jack alloc]init];
    
    
    mydog.taker = me;                   //내가 개를 돌봐줄때
    //mydog.taker = Jack;               // 잭이 개를 돌봐줄때
    
    
    [mydog isHungry];					//강아지가 배고플때
    
    [mydog wantToGoOut];				//강아지가 나가고 싶을때
    
}
@end

ProtocolTest[2166:588134] 좋아, 밥줄게~ 밥먹자~~
ProtocolTest[2166:588134] 좋아, 나가서 놀자~!

실행하는 부분에서 강아지, 나의 객체를 만든다. 그리고 강아지 객체에게 돌봐주는 사람을 '나'로 할당한다. 그리고 강아지의 isHungry, wantToGoOut 메소드를 실행한다. 그럼 강아지는 _taker 객체를 이용해서 돌봐주는 사람의 메소드를 호출한다. 그러면 돌봐주는 사람은 메소드에 구현된 액션을 취한다. '좋아, 밥줄게~ 밥먹자~' 등~~

시나리오2)
때로는 내가 바쁠때가 있다. 그럴때 나의 친구 잭이 나의 강아지를 돌봐준다. 이럴때 어떻게 해야할까? Me. 라는 클래스를 생성했던것 처럼, Jack이라는 클래스를 생성하고 Me 클래스에 구현했던 메소드를 동일하게 구현해준다. 로그만 바꿔준다. '그래, 고기먹자!, 그래 나가보자!' 
이렇게 되면 문제가 있다. 강아지.h, 강아지.m 에서 Me 클래스를 임포트해서 사용했는데 이제는 Jack 클래스를 가져와야 한다. 그리고 실행부분에 jack 객체를 만들어 주고 mydog.taker = Jack 처럼 나의 강아지를 돌봐주는 사람으로 잭을 셋팅해주어야 한다. 아래와 같다. 

//강아지.h

#import <Foundation/Foundation.h>
// 삭제 @class Me;  //나
@class Jack;   //잭!

@interface MyDog : NSObject

// 삭제 @property (nonatomic, strong) Me *taker;    //돌봐주는 사람
@property (nonatomic, strong) Jack *taker;    //잭!

- (void) wantToGoOut;                       //나가 놀고 싶다.
- (void) isHungry;                          //배고프다
@end


//강아지.m

#import "MyDog.h"
// 삭제 #import "Me.h"
#import "Jack.h"

@implementation MyDog

//나가고 싶어할때
- (void) wantToGoOut{
    
   [_taker myDogSayWow:self];		//돌봐주는 사람에게 와우라고 소리친다.
}

//배고플때
- (void) isHungry{
     [_taker myDogDidLookHopeful:self];	//돌봐주는 사람을 쳐다본다.
    
}
@end

ProtocolTest.zip
0.05MB

시나리오3)
이렇게 작성해주는것도 나쁘지 않다. 하지만 돌봐주는 사람이 늘어날때마다 강아지 클래스 파일 맨위에 #import...를 나, 잭 .. @class 나, 잭 으로 변경해야한다. 이런 상황에서 mydog.h 에 프로토콜을 사용해 볼 수 있다. 

강아지.h

#import <Foundation/Foundation.h>


@class MyDog;
//@class Me;  //나

//프로토콜 선언!
@protocol MyDogDelegate <NSObject>
//강아지가 기대하며 쳐다본다.
-(void) myDogDidLookHopeful:(MyDog *) mydog;

//강아지가  와우라고 짓는다.
-(void) myDogSayWow:(MyDog *) mydog;
@end

@interface MyDog : NSObject

@property (nonatomic, strong) id <MyDogDelegate> delegate;    //돌봐주는 사람 - > MyDogDelegate 변경!! ! 중요!!

- (void) wantToGoOut;                       //나가 놀고 싶다.
- (void) isHungry;                          //배고프다

@end

강아지.m

#import "MyDog.h"
//#import "Me.h"


@implementation MyDog

//나가고 싶어할때
- (void) wantToGoOut{
    
   [_delegate myDogSayWow:self];               //돌봐주는 사람에게 와우라고 소리친다.
}

//배고플때
- (void) isHungry{
     [_delegate myDogDidLookHopeful:self];     //돌봐주는 사람을 쳐다본다.
    
}
@end

나.h

#import <Foundation/Foundation.h>
#import "MyDog.h"

//@class MyDog;

@interface Me : NSObject <MyDogDelegate> //강아지.h에서 선언한 프로토콜 상속

//강아지가 나를 기대하며 쳐다본다.
-(void) myDogDidLookHopeful:(MyDog *) mydog;

//강아지가 나에게 와우라고 짓는다.
-(void) myDogSayWow:(MyDog *) mydog;
@end


jack.h

#import <Foundation/Foundation.h>
#import "MyDog.h"
//@class MyDog;

@interface Jack : NSObject <MyDogDelegate>
//강아지가 잭을 기대하며 쳐다본다.
-(void) myDogDidLookHopeful:(MyDog *) mydog;

//강아지가 잭에게 와우라고 짓는다.
-(void) myDogSayWow:(MyDog *) mydog;
@end


ViewController.m

#import "ViewController.h"

#import "Me.h"
#import "MyDog.h"
#import "Jack.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    
    MyDog *mydog = [[MyDog alloc]init];     //강아지
    Me *me = [[Me alloc]init];              //나
    Jack *jack = [[Jack alloc]init];
    
    //mydog.delegate = me;					//델리게이트로 호출!!!!
     mydog.delegate = jack;
    //mydog.taker = me;                   //내가 개를 돌봐줄때
    //mydog.taker = Jack;               // 잭이 개를 돌봐줄때
    
    
    [mydog isHungry];
    
    [mydog wantToGoOut];
    
 
}


@end

ProtocolTest 2.zip
0.05MB

반응형

댓글