본문 바로가기
⌨️ Language/swift

[Swift] 프로토콜

by hyebin (Helia) 2024. 3. 29.

프로토콜(Protocols)

  • 어떤 기능에 필요한 요구사항을 선언해두는 것
  • 클래스, 구조체, 열거형에 의해 채택

프로토콜 문법

protocol SomeProtocol {
// protocol definition
}

프로토콜을 따르는 타입을 정의하기 위해서는 타입 이름 뒤에 콜론(:)을 붙이고 프로토콜 이름을 적음

프로토콜을 채택할 때는 프로토콜에 정의된 요구사항을 반드시 구현 해야만 함

 

struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // class definition goes here
}

프로토콜 요구사항 정의

프로퍼티 요구사항

  • 프로퍼티의 이름과 타입 그리고 gettable, settable 한지 명시해야 함
  • 연산 프로퍼티는 항상 var로 선언해야함(저장 프로퍼티는 gettable 만 가능한 경우에는 let으로 선언 가능), 타입 프로퍼티는 static 키워드 사용
protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
		static var someTypeProperty: Int { get set }
}

 

메소드 요구사항

  • 필수 인스턴스 메소드와 타입 메소드 명시 가능
  • 메소드 파라미터의 기본값은 사용 불가
protocol SomeProtocol {
    static func someTypeMethod()
    func random() -> Double
}

 

변경 가능한 메소드 요구사항

  • mutating 키워드를 사용해 인스턴스에서 변경 가능하다는 것을 표시
  • mutating 키워드는 값 타입에서만 사용
protocol Togglable {
    mutating func toggle()
}

 

초기자 요구사항

  • 프로토콜에서 필수로 구현해야하는 이니셜라이저 지정 가능
  • 구현할 때 이니셜라이저 앞에 required 키워드를 붙여줘야함
protocol SomeProtocol {
    init(someParameter: Int)
}

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // initializer implementation goes here
    }
}
  • 프로토콜을 채택하고 클래스를 상속받는 경우 이니셜라이저 앞에 required 키워드와 override 키워드를 적어야함
protocol SomeProtocol {
    init()
}

class SomeSuperClass {
    init() {
        // initializer implementation goes here
    }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
    // "required" from SomeProtocol conformance; "override" from SomeSuperClass
    required override init() {
        // initializer implementation goes here
    }
}

 

타입으로써의 프로토콜

프로토콜도 타입으로 사용가능

  • 함수, 메소드, 이니셜라이저의 파라미터 타입 혹은 리턴 타입
  • 상수, 변수, 프로퍼티의 타입
  • 컨테이너인 배열, 사전 등의 아이템 타입

프로토콜 위임

클래스 혹은 구조체 인스턴스에 특정 행위에 대한 책임을 넘길 수 있게 해주는 디자인 패턴

 

익스텐션의 사용

  • 이미 존재하는 타입에 새 프로토콜을 따르게 하기위해 익스텐션을 사용
  • 원래 값에 접근 권한이 없어도 익스텐션을 사용해 기능 확장 가능
protocol TextRepresentable {
    var textualDescription: String { get }
}

 

조건적으로 프로토콜 따르기

where 키워드를 사용해 특정 조건을 만족시킬 때만 프로토콜을 따르도록 제한

 

프로토콜 타입 컬렉션

프로토콜을 collection 타입에 넣기위한 타입으로 사용가능

let things: [TextRepresentable] = [game, d12, simonTheHamster]

for thing in things {
    print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon

 

프로토콜 상속

클래스 상속같이 프로토콜도 상속 가능, 콤마(,)로 구분

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
    // protocol definition goes here
}

 

클래스 전용 프로토콜

프로토콜에 AnyObject를 추가

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

 

프로토콜 합성

동시에 여러 프로토콜을 따르는 타입을 선언 가능

protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
    print("Happy birthday, \\(celebrator.name), you're \\(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Prints "Happy birthday, Malcolm, you're 21!"

 

프로토콜 순응 확인

어떤 타입이 특정 프로토콜을 따르는지 다음과 같은 방법으로 확인 가능

  • is연산자를 이용하면 어떤 타입이 특정 프로토콜을 따르는지 확인가능
    • 특정 프로토콜을 따르면 true를 아니면 false를 반환합니다.
  • as?는 특정 프로토콜 타입을 따르는 경우 그 옵셔널 타입의 프로토콜 타입으로 다운캐스트를 하게 되고 따르지 않는 경우는 nil을 반환
  • as!는 강제로 특정 프로토콜을 따르도록 정의
    • 만약 다운캐스트에 실패하면 런타임 에러가 발생

선택적 프로토콜 요구조건

  • 선택적 구현 조건을 정의 가능
  • @objc 키워드를 프로토콜 앞에 붙이고 개별 함수 혹은 프로퍼티에는 @objcoptional 키워드 사용
    • @objc 프로토콜은 클래스 타입에서만 사용될 수 있고 구조체나 열거형에서는 사용할 수 없음
@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}

 

프로토콜 익스텐션

익스텐션을 사용해 프로토콜 확장가능

기본 구현 제공

  • 익스텐션을 기본 구현을 제공하는데 사용 가능
  • 프로토콜에서는 선언만 할 수 있는데 익스텐션을 이용해 기본 구현을 제공
extension PrettyTextRepresentable  {
    var prettyTextualDescription: String {
        return textualDescription
    }
}

프로토콜 익스텐션에 제약 추가

  • 익스텐션이 특정 조건에서만 적용되도록 where 절을 사용해 선언 가능
extension Collection where Element: Equatable {
    func allEqual() -> Bool {
        for element in self {
            if element != self.first {
                return false
            }
        }
        return true
    }
}
반응형

'⌨️ Language > swift' 카테고리의 다른 글

[Swift] 자동 참조 카운트  (0) 2024.04.02
[Swift] 제네릭  (0) 2024.04.02
[Swift] 에러 처리  (0) 2024.03.28
[Swift] 옵셔널 체이닝  (0) 2024.03.26
[Swift] 초기화  (1) 2024.03.25

댓글