프로토콜

  • 프로토콜이란? 일종의 강제사항으로 해당 프로토콜을 채택한 객체는 프로토콜이 요구하는 내용을 반드시 준수해야만 한다.
  • 프로토콜은 단순한 선언 형태로만 작성되며 구체적인 내용은 프로토콜을 채택한 객체가 담당한다.
  • 프로토콜은 프로토콜을 상속받을 수 있다. 그리고 프로토콜은 다중상속이 가능하다.
  • 프로토콜은 static, mutating 등의 키워드 사용이 가능하다.
protocol Test {
    var number: Int { get set } //읽고 쓰기가 가능한 저장 프로퍼티 선언
    var number2: Int { get } //읽기만 가능한 연산 프로퍼티로 선언
    
    func add(num1: Int, num2: Int) -> Int //정수타입을 매개변수로 하여 정수를 반환하는 메소드를 선언
}

class A: Test {
    var name: String = "이름" //새로운 프로퍼티
    var number: Int = 10 //저장 프로퍼티 구현(프로토콜 요구사항)
    var number2: Int { //연산 프로퍼티 구현(프로토콜 요구사항)
        get {
            return 3
        }
    }
    
    func add(num1: Int, num2: Int) -> Int { //메소드 구현(프로토콜 요구사항)
        return num1 + num2
    }
}
  • 프로토콜이 요구하는 내용을 준수하기만 한다면, 새로운 프로퍼티나 메소드를 추가하는 것은 상관이 없다.
  • 이처럼 프로토콜은 채택한 객체가 그 구현을 담당한다.

프로토콜의 초기화 메소드

  • 클래스나 구조체에서 아무런 초기화 메소드를 정의하지 않을 경우 기본적으로 제공되는 초기화 메소드도 프로토콜에 정의되어 있다면 반드시 구현해야 한다.
  • 클래스에서 초기화 메소드를 구현할 때에는 반드시 required 키워드를 붙여야 한다.
protocol A {
    init()
    init(name: String)
}

struct B: A {
    var name: String?
    
    init() {
        self.name = "default"
    }
    
    init(name: String) {
        self.name = name
    }
}

class C: A {
    var name: String?
    
    required init() {
        self.name = "default"
    }
    required init(name: String) {
        self.name = name
    }
}
  • 클래스의 경우 상속과 프로토콜 채택이 동시에 가능하기 때문에 상속과 채택에 따른 override와 required를 동시 써야한다.
  • 이때 작성되는 순서는 중요하지 않다.
protocol A {
    init()
}

class B {
    init () {
    }
}

class C: B, A {
    override required init() {
    }
}

클래스와 프로토콜

  • 클래스 전용 프로토콜을 선언할 수 있는데, 이때에는 프로토콜 이름 다음에 class를 추가한다.
  • 또한, 클래스 전용 프로토콜의 경우 옵셔널로 선언한 내용에 대해서는 반드시 구현하지 않아도 된다.
  • 옵셔널로 선언할 경우에는 반드시 @objc 키워드를 추가해야 한다.
import Foundation

@objc
protocol A: class {
    @objc optional var name: String { get set }
}

class B: A {
}
  • 이처럼 옵셔널 변수 name의 구현은 구현하는 객체의 자유이다.