iOS/Swift

Swift) Protocol 이해하기 (4/6) - Protocol Extension

소들이 2022. 11. 15. 19:34

 

 

안녕하세요, 소들입니다 XD

프로토콜 포스팅이 훔 .. 생각보다 한두편 정도 더 늘어날 수도 있겠더라구요

내용이 왤케 많고 난리임

쨌든 이번 포스팅에선 Protocol Extension(프로토콜의 확장)!에 대해서 공부해볼 거예요

이 프로토콜의 확장은 생각보다 자주 쓰이는 문법이랍니다!

그럼 공부하러 가봅시다 :)

모든 포스팅은 편의 말투로 합니다~!!

 

 

 

 

1. 상속 대신 프로토콜을 사용할 때의 불편함을 느낀다면,,

 

여러분 

우리가 만약 늘 등장하는 Band라는 프로토콜을 만들었음

 

 

protocol Band {
    func play()
}

 

 

밴드라면 당연히 연주는 해야지! 하고 play라는 메서드를 프로토콜에 정의 했음

그리고 다음과 같이 ABand, BBand, CBand 구조체가 모두 Band는 프로토콜을 채택 함

 

 

struct ABandBand {
    func play() {
        print("play!")
    }
}
 
struct BBandBand {
    func play() {
        print("play!")
    }
}
 
struct CBandBand {
    func play() {
        print("play!")
    }
}

 

 

세 구조체 모두 Band 프로토콜과의 약속을 지키기 위해

play란 메서드를 각자 구현 했음

 

근데!!! 아닛 구현해놓고보니!!

모두 공통적으로 play 메서드를 동일하게 구현하고 있음

한 마디로 Band에서 정의한 play라는 메서드는

특별한 일이 없는 한..! 기본적으로

 

print("play!")

 

를 실행 하는 메서드였떤 것임..!

아니 근데 그러면..

저 똑같은 메서드를 Band를 채택하는 프로토콜마다 다 구현해줘야 하나요!?!?!

이런이런,, 비효율적인걸..

 

만약.. 클래스라면..! 상속이 된다면..!

부모 클래스에서 정의하고 자식 클래스는 별도로 정의 없이 갖다 쓰기만 하면 되는데..

괜히 프로토콜로 구현해서 모든 클래스마다 

공통된 기능을 다 구현해야 하잖아여!!

 

라고 생각할 수 있잖음?

근데 프로토콜이 뭐 빙다리 핫바지도 아니고

Swift에서 클래스보다 프로토콜이 훨씬 중요도가 높은 만큼

당연히 기본 기능의 메서드를 프로토콜도 지원할 수 있음!!

어떻게?

 

extension! 확장!을 통해!!

 

 

 

 

2. 확장을 통해 프로토콜 메서드의 기본 구현을 제공하세요

 

위에서 기본적으로 play란 메서드의 기본 기능이 채택하는 곳마다 같았잖음?

이처럼 프로토콜에서 기본적으로 구현을 제공해주고 싶을 경우,

extension을 통해서 제공할 수 있음

 

 

protocol Band {
    func play()
}
 
extension Band {
    func play() {
        print("play!")
    }
}

 

 

이렇게 프로토콜에 extension을 해주고,

기본적으로 제공하고 싶은 기능(메서드)를 직접 위처럼 extension 내부에 구현 해줘버리는 것임

 

이렇게 할 경우,

해당 Protocol을 채택한 곳에서 직접 play()라는 메서드를 더이상 구현하지 않아도 됨

왜냐?? 만약 구현하지 않을 경우,

extension에 미리 구현된 play()가 불리게 되그등요!!!

 

 

struct ABandBand { }
 
ABand().play()                  // "play!"

 

 

이렇게!!

ABand 구조체는 Band를 채택했지만, play() 메서드를 ABand에서 직접 구현하지 않아도 됨

대신 이땐, play() 메서드를 호출할 경우 extension에 구현된 play()가 호출 됨!!

 

에에 근데 저는요

기본으로 제공하는 메서드 사용 안 하고, 제가 직접 play()를 구현 하고 싶은데요??

하면, 기존처럼 그냥 구현해주면 됨

 

 

struct BBandBand {
    func play() {
        print("BBand play!")
    }
}

BBand().play()                  // "BBand play!"

 

 

이렇게 직접 구현할 경우,

extension에 구현된 기본 제공되는 play()보다, 직접 구현한 play()의 우선순위가 높기 때문

내 클래스/구조체/열거형 안에 직접 구현한 놈으로 불린답니다!!

 

 

 

+ 또한 where을 통해서 기본 메서드를 제공하는 것에 제한을 둘 수도 있음!

 

 

protocol Human { }
protocol Band {
    func play()
}
 
extension Band where SelfHuman {
    func play() {
        print("play!")
    }
}
 

 

 

위처럼 where을 통해서 제한을 둘 경우,

Human 클래스를 채택하고 있는 경우에만 확장을 제공하겠다! 라는 뜻이 되고,

 

따라서,

 

 

struct ABandBand { }
ABand().play()                  // X! Type 'ABand' does not conform to protocol 'Band'
 
struct BBand: HumanBand { }
BBand().play()                  // O! "play!"
 

 

 

이렇게 

Human 프로토콜을 채택하지 않은 ABand의 경우 extension에 구현된 기본 메서드가 제공되지 않기 때문에,

ABand는 play() 메서드를 구현하라!!!!! 하고 에러가 뜨는 것이고,

Human 프로토콜을 채택하고 있는 BBand의 경우 extension에 구현된 기본 메서드가 제공되기 때문에,

BBand는 play()메서드를 구현하지 않아도 기본 메서드를 사용할 수 있음

 

 

 

 

3. 메서드만 확장 되나요? 프로퍼티도 기본 값 extension으로 주면 안 되나요?

 

extension의 경우, 프로퍼티를 추가하고 싶다면 연산 프로퍼티만 가능 하자나요??

그렇다면 extension을 통해 프로토콜에 선언된 프로퍼티를

연산 프로퍼티로 구현해서 기본값을 지니게 해놓으면 안되나요??

 

라고 생각 해서 해봤는데

 

 

protocol Band {
    var piano: String { get }
}
 
extension Band {
    var piano: String {
        return "sodeul"
    }
}
 
struct ABandBand {}             
 
 

 

 

잘 되네염ㅎㅎㅎㅎ!!!!!!11

바보같이 get set 해놓고 getter만 구현해놔서 안 되는 줄 알았는데!

형식만 잘 지켜주면 프로퍼티도 잘 적용 된답니다!!! :)

extension에서 프로퍼티를 추가할 땐 연산 프로퍼티만 가능하단 점만 잘 유의해두시면 될듯 합니당!!

 

 

 

 

 

 

.

.

.

프로토콜의 확장에 대해 포스팅 끝~_~!!!!

음... 한두편 늘어날 것 같군 허허

잘못된 내용이나 오타 및 궁금증은 언제나 댓글 주세용~~!