본문 바로가기
Swift

Protocol에 관하여

by iOS 개린이 2022. 11. 14.

1. Protocol(프로토콜)

-프로토콜은 특정 기능을 수행하기 위한 메서드, 프로퍼티 등 요소들을 정의해 놓은 청사진을 말한다. 

-프로토콜은 정의와 제시를 할 뿐 원하는 특정 기능 구현을 제공하지는 않고, 클래스, 구조체 또는 열거형에서 프로토콜을 채택하여 특정 기능을 실제 구현할 수 있다.

 

ex) 프로토콜 정의

protocol Example {
         
}

 

ex) 프로토콜 채택

struct ExamStruct : Example {
  
}

class ExamClass : Example {
   
}

enum ExamEnum : Example {
   
}

 

-extension을 통해 프로토콜에 추가적인 기능을 더해줄 수 있다.

-다른 프로토콜을 상속받을 수도 있다.(다중 상속도 가능)

 

 

프로토콜에서 프로퍼티 요구사항

1. 이름과 타입만 명시해주어야 하고(프로토콜은 정의나 제시만 할 뿐),

2. 각 프로퍼티에 읽기 전용으로 할지 쓰기 전용으로 할 지 get과 set을 명시해주어야 하고,

3. 선언 시 항상 var로 선언해야 한다.

 

ex) 프로퍼티 선언

protocol TestProcotol {

     var testProperty : Int {get} 
     
     var secondTestProperty : Int {get, set}
     
     static var thirdTestProperty : Int {get, set}  //타입 프로퍼티
}

 

클래스의 타입 프로퍼티에는 상속이 가능한 class 타입과 상속이 불 가능한 static 타입이 있는데, 프로토콜에서는 이를 구분하지 않고 static을 사용한다.

 

 

ex) 프로토콜 채택

struct Example : TestProtocol {
   var testProperty : Int
   
   var secondTestProperty : Int
   
   static var thirdTestProperty : Int = 0   //타입 프로퍼티는 이니셜라이저가 필요 
}

 

위의 코드에서 TestProtocol의 프로퍼티 요구사항을 구조체 Example이 준수하고 있는 것!

프로토콜은 프로퍼티가 저장 프로퍼티인지, 연산 프로퍼티인지 명시할 필요없이 이름과 타입만이 요구된다!

 

프로토콜에서 프로퍼티를 명시할 때 gettable만 명시할 때와 gettable/settable 모두 명시했을 때의 차이

 

protocol TestProtocol {
    var name : String {get}
}

 

위의 코드와 같이 프로퍼티를 get으로만 명시해주면 모든 종류의 프로퍼티에서 요구사항을 충족시킬 수 있다. (요구사항을 정의해줄 때 let 저장 프로퍼티든 var 저장 프로퍼티든, get이든 set이든 모두 충족)

 

 

ex) let과 var 저장 프로퍼티

struct Person : TestProtocol {
   let name : String = "Lim"
}

struct Person : TestProtocol {
   var name : String = "Lim"
}

 

let으로 정의하든 var로 정의하든 모두 가능!

 

 

ex) get과 set 

struct Person : TestProtocol {
   var name : String          
   
   var myName : String {      //get 
      return name
   }set {
      name = newValue         //set 
   }
}

var jisu = Persom(name : "jisu")
jisu.myName = "taehwan"  //set 가능
print(jisu.myName)      //get 가능

 

위의 코드와 같이 get으로 명시했을 때 let과 var 저장 프로퍼티, get과 set 연산 프로퍼티 모두 충족된다.

 

하지만 gettable/settable 로 명시했을 때는 모두 충족시킬 수 없다.

ex) get/set으로 명시했을 때

protocol TestProtocol {
    var name : String {get set}
}

 

ex) 저장 프로퍼티로 요구사항 구현할 때

struct Person : TestProtocol {
   let name : String = "Lim"  //'let' 으로 선언된 저장 프로퍼티 error 발생!!
}

 

 

let으로 저장프로퍼티 충족은 불가!

 

 

ex) get 전용 연산프로퍼티로 요구사항 구현할 때

struct Person : TestProtocol {
   var name : String          
   
   var myName : String {      //gettable 만 충족하면 error 발생! 
      return name
   }
}

 

get 전용 연산프로퍼티로 요구사항 충족 불가! get/set 모두 충족해주어야 한다.

 

 

프로토콜에서 메서드 요구사항

-프로토콜에서 메서드는

1. 타입 메서드와 특정 인스턴스 메서드를 요구할 수 있다.

2. 메서드의 실제 구현 부인 중괄호와 본문은 제외한다. (매개변수나 반환타입은 작성 가능)

 

protocol TestProcotol {

     static func testTypeMethod()
     
     func test() -> Double                    // {}는 입력안해줌.
}

 

ex) 채택할 때

class Example: TestProtocol {
    
    static func testTypeMethod() {
    }
    
    func test() -> Double {
        return 5.5
    }
}

 

채택하는 곳에서 함수의 바디를 직접 구현!

 

 

Mutating 메서드 요구사항

Value Type인 구조체나 열거형의 메서드 앞에 "mutating" 을 붙여주면 프로퍼티의 값을 자유롭게 수정해 줄 수 있다. 

프로토콜에서도 mutating 키워드를 붙여 메서드를 명시해주면, 구조체나 열거형에서 채택할 때 프로퍼티 수정이 가능한 메서드를 사용할 수 있다.

 

ex) struct에서 protocol 채택할 때

protocol ChangeNameProtocol {
   mutating func changeName(name : String) 
}

struct Person : ChangeNameProtocol {
   var name : String = "jisu"

   mutating func changeName(newName : String) {
       name = "\(newName) + \(name)"
   }
}

 

이렇게 Value Type에서 보통 메서드라면 메서드 안에서 프로퍼티의 값을 변경해줄 수 없지만, mutating을 통해서 수정가능해졌다.

 

 

ex) class에서 mutating이 있는 protocol을 채택할 때

class Person : ChangeNameProtocol {
   var name : String = "jisu"

   func changeName(newName : String) {
       name = "\(newName) + \(name)"
   }
}

 

class에서 채택할 때는 mutating을 붙이지 않아도 된다. 왜냐면 class는 Reference Type이기 때문에 애초에 mutating이 있던 말던 메서드에서 프로퍼티의 값을 변경하는 것이 가능하다!

 

 

 

 

 

 

 

 

참고:

프로토콜 (Protocols) - The Swift Language Guide (한국어) (gitbook.io)

Swift ) Protocols (1) (tistory.com)

Swift ) Protocols (2) (tistory.com)

Swift) Protocol 이해하기 (2/5) - 프로퍼티 / 메서드 선언 이해하기 (tistory.com)

 

 

 

'Swift' 카테고리의 다른 글

오버라이딩(Overriding)에 관하여  (0) 2023.01.26
제네릭(Generic)에 관하여  (0) 2022.11.23
lazy variables에 관하여  (0) 2022.10.07
순환참조에 관하여  (0) 2022.09.28
@escaping에 관하여  (0) 2022.08.25