EEYatHo 앱 깎는 이야기

Swift ) Protocol ( 프로토콜 ) - EEYatHo iOS 본문

iOS, Swift/Swift Theory

Swift ) Protocol ( 프로토콜 ) - EEYatHo iOS

EEYatHo 2021. 7. 22. 21:14
반응형

 

프로토콜이란?


  • 특정 역할을 하기 위한, 메소드, 프로퍼티, 기타 요구사항 등의 청사진.
  • 프로토콜은 정의를 제시하지 기능 구현은 안함. (추상의 클래스 역할)

 

 

프로토콜의 장점


  • 2015년 9월, WWDC에서 스위프트 버전 2.0을 발표하면서,
    스위프트는 프로토콜 지향 언어(Protocol-Oriented Language) 라 칭함
  • 레퍼런스 시멘틱스(class)는 추적에 많은 비용이 들어감.
    => 프로토콜을 이용하면 값 시멘틱스(struct)로 캡슐화, 추상화를 할 수 있다.
  • 프로토콜 익스텐션의 초기구현을 사용하여 재사용성도 챙길 수 있다.
  • 테스트시, Mocking 을 쉽게 할 수 있다.
    ( 테스트할 모듈은 구현체로, 다른 모듈은 Protocol을 채택하고 테스트 결과를 확인할 수 있는 Mock 으로 사용. )
  • Swift 에서 class 는 1개만 상속받을 수 있지만, Protocol 은 여러개를 채택할 수 있다. ( 다중 상속 구현 )

 

 

프로토콜의 사용


  • struct, class, enum, actor 에서 프로토콜을 채택.
  • 함수의 파라미터나, 리턴타입, 프로퍼티의 타입 등으로 사용 가능하며, 해당 프로토콜을 채택한 타입을 뜻한다.

 

 

예시와 디테일한 옵션들


1. 기본형태

protocol 프로토콜이름 {  
    프로토콜 정의  
}

 

2. 클래스에서만 채택가능하게 하기

protocol 프로토콜이름: AnyObject {  // : class 는 Deprecated
    프로토콜 정의  
}

+ 클래스에서만 채택가능하다고 명시하지 않은채로, weak 로 선언하면 오류발생  => AnyObject 채택 필요

   ( 구조체나 열거형 같은 value sementics 는 weak 선언이 불가능하기 때문 ) 

protocol SomeProtocol { }

struct SomeStruct {
    weak var delegate: SomeProtocol?
    // 'weak' must not be applied to non-class-bound 'any SomeProtocol'; consider adding a protocol conformance that has a class bound
}

 

 

3. 클래스에서 부모 클래스와 프로토콜 채택을 모두 표시할 경우, 부모클래스를 먼저 명시해야함.

class SomeClass: SuperClass, SomeProtocol {  
    클래스 정의   
}

 

4. 프로퍼티는 항상 var로 선언하며, 이름, 타입, gettable여부, settable여부를 명시.

protocol Student {  
    var height: Double { get set }  
    var name: String { get }  
    static var schoolNumber: Int { get set }  
}

 

5. 메소드 앞에 mutating 키워드를 붙혀서, 인스턴스를 변경하는 메소드임을 알림.

protocol Person {
  static func breathing()
  func sleeping(time: Int) -> Bool
  mutating func running()
}

struct Aiden: Person {
    var heartRate = 100
    static func breathing() {
        print("숨을 쉽니다")
    }
    
    func sleeping(time: Int) -> Bool {
        if time >= 23 {
            return true
        } else {
            return false
        }
        
    }
    
    mutating func running() {
        heartRate += 20
    }
}

 

6. 프로토콜에서 생성자 정의도 가능. 프로토콜을 채택한 이상, 꼭 구현해야하는 생성자임으로, required를 붙혀준다.

protocol SomeProtocol {
  init(someParameter: Int)
}
class SomeClass: SomeProtocol {
  required init(someParameter: Int) {
    // 구현부
  }
}

 

7. extension 으로 프로토콜에도 함수를 구현할 수 있다. (= 초기구현) 

  • 주의사항으로, 프로토콜을 채택한 클래스(or 구조체) 가 초기구현을 오버라이딩 해도,
    호출부에서 타입이 프로토콜이라면, 프로토콜의 함수가 호출된다.
  • 클래스(or 구조체)로 타입캐스팅하면, 클래스(or 구조체)의 함수를 호출한다.
protocol SomeProtocol { }
extension SomeProtocol {
    func someFunc() {
        print("protocol")
    }
}

class SomeClass: SomeProtocol {
    func someFunc() {
        print("class")
    }
}

let classProperty = SomeClass()
let protocolProperty: SomeProtocol = SomeClass()

classProperty.someFunc()
protocolProperty.someFunc()
(protocolProperty as? SomeClass)?.someFunc()
// class
// protocol
// class

 

Comments