프로토콜은 어떤 역할을 위해서 메서드, 프로퍼티 등에 대한 틀을 말한다. 프로토콜을 만들면(틀을 생성하면) 구조체, 클래스, 열거형은 만든 프로토콜을 채택해서 프로토콜의 요구사항을 구현할 수 있다.
기본적인 형태는 다음과 같다.
protocol 프로토콜명 {
// 프로토콜 정의
}
이렇게 정의한 프로토콜을 채택하는 방법은 다음과 같다.
struct 구조체명: 프로토콜1, 프로토콜2 {
// 구조체 정의
}
class 클래스명: 상속받을 클래스명, 프로토콜1, 프로토콜2 {
// 클래스 정의
}
enum 열거형명: 프로토콜1, 프로토콜2 {
// 열거형 정의
}
위 예제처럼 여러 개의 프로토콜을 동시에 채택할 수 있으며 프로토콜 내의 정의된 부분만 구현해주면 된다. 클래스가 상속받는 클래스가 존재할 경우엔 위의 클래스 예제처럼 상속받을 클래스를 넣어주고 이어 프로토콜을 작성해주면 된다.
프로토콜 내의 정의는 프로퍼티나 메서드 같은 기능들이다.
만약, 프로토콜이 프로퍼티를 요구한다면 그 프로퍼티는 항상 var
(변수) 키워드를 사용해야 한다. 그리고 뒤에 읽기 전용이면 { get }
, 읽기와 쓰기가 가능하면 { get set }
을 작성해주어야 한다.
클래스에서 class
타입 프로퍼티와 static
타입 프로퍼티가 있는데 프로토콜 내에서는 따로 구분하지 않고 static
키워드만 사용해서 타입 프로퍼티를 요구한다.
protocol 프로토콜명{
static var 프로퍼티명: 타입 { get } // 읽기 전용 타입 프로퍼티
var 프로퍼티명: 타입 { get set } // 읽기, 쓰기 가능 프로퍼티
}
메서드 요구도 프로퍼티 요구와 같다.
하지만, 값 타입(구조체, 열거형)의 인스턴스 메서드에서 내부 값을 변경하려고 할 경우 func 키워드 앞에 mutating
키워드를 붙여주면 된다. 참조 타입인 클래스의 경우에는 안 붙여줘도 내부의 값을 변경할 수 있다.
protocol 프로토콜명 {
func 메서드명(매개변수)
static func 메서드명(매개변수)
mutating func 메서드명(매개변수)
}
이니셜라이저 요구도 작성할 수 있다. 일반적으로 프로퍼티나 메서드처럼 틀만 만들어주면 된다. 하지만 클래스의 경우에는 상속이라는 것이 존재하기 때문에 요구에 맞는 이니셜라이저를 구현하려면 required
키워드를 붙여 구현을 해야한다. 상속때문이라면 상속도 하고 이니셜라이저 요구도 맞춰 이니셜라이저를 구현한다면 override
키워드도 붙여서 required override
또는 반대로 사용하면 된다.
그럼 final
키워드가 붙어서 상속을 받을 수 없는 클래스의 경우엔 어떻게 해야하나?
당연히 required
키워드를 붙일 필요가 없다.
protocol 프로토콜명 {
var 프로퍼티: 타입 { get }
init(매개변수: 타입)
}
class 클래스명A {
init(매개변수: 타입){
// 생성자 정의
}
}
class 클래스명B: 클래스명A, 프로토콜명 {
var 프로퍼티: 타입
ovrride required init(매개변수: 타입) {
// 생성자 정의
}
}
프로토콜도 클래스처럼 상속을 받을 수도 있다. 그럼 상속받은 프로토콜을 클래스에서 채택하면 프로토콜이 상속받은 다른 프로토콜들의 정의또한 클래스에서 구현해주어야 한다.
그리고, 클래스 전용 프로토콜도 만들어줄 수 있다. 바로 프로토콜의 상속 리스트에 class
키워드를 적어주면 클래스만 해당 프로토콜을 채택할 수 있도록 할 수 있다.
protocol 프로토콜A{
func 메서드A()
}
protocol 프로토콜B: class, 프로토콜 A{
func 메서드B()
}
class 클래스: 프로토콜B {
func 메서드A() {
// 메서드 구현
}
func 메서드B(){
// 메서드 구현
}
}