본문 바로가기
Swift

[Swift] 프로토콜 (Protocol)

by Sky Titan 2021. 1. 2.
728x90
스위프트 프로그래밍
국내도서
저자 : 야곰
출판 : 한빛미디어 2019.10.01
상세보기

프로토콜 (Protocol)

  • 특정 역할을 하기 위한 메서드, 프로퍼티, 기타 요구사항 등의 청사진을 정의하는 것
  • 구조체, 클래스, 열거형은 프로토콜을 '채택(Adopted)' 해서 특정 기능을 실행하기 위한 프로토콜의 요구사항을 실제로 구현할 수 있다. 
  • 특정 타입이 특정 프로토콜을 채택하고 따르고 있으면 '준수 (Conform)' 한다고 표현한다.
  • 프로토콜은 정의를 하고 제시만 할 뿐, 스스로 기능을 구현하진 않음

 

프로토콜 요구사항

1. 프로퍼티 요구 (Property)

  • 프로토콜을 채택한 타입은 프로토콜이 요구하는 프로퍼티의 이름과 타입만 맞도록 구현하면 된다.
    • 연산, 저장 종류는 신경쓰지 않아도된다.
  • 프로퍼티 요구사항은 항상 var 키워드를 쓰는 변수 프로퍼티 사용
    • 읽기, 쓰기 모두 가능 프로퍼티 : {get set}
    • 읽기 전용 프로퍼티 : {get}
  • 타입 프로퍼티를 요구할 시엔 static 키워드 사용
import Foundation

protocol Animal {
    var name: String {get set} //읽기, 쓰기 모두 가능
    var age: Int {get} //읽기만
}

class Human: Animal {
    var name: String = "Park"
    var age: Int {
        return 15 
    }
}

let p1: Human = Human()
print(p1.name)
p1.name = "kim"
p1.age = 16//error 발생
print(p1.name)
print(p1.age)

 

2. 메서드 요구 (Method)

  • 메서드의 실제 구현부인 { } 블록 부분은 제외하고 메서드 이름, 매개변수, 반환 타입만 작성한다.
  • 매개변수 기본값 지정 불가능
  • 타입 메서드 선언 시 static 혹은 class 키워드 사용
  • 인스턴스 내부의 값을 변경하는 가변 메서드의 경우 mutating 사용
    • 클래스에서 구현할 때는 mutating 안 붙여도 됨.
    • 프로토콜에서 가변 메서드를 요구하지 않는다면 구현 시에 내부 값 변경 불가능
import Foundation

protocol Animal {
    var name: String {get set} //읽기, 쓰기 모두 가능
    var age: Int {get set} //읽기만

    func sayNameAndAge()

    mutating func addAge(amount: Int)
}

struct Human: Animal {
    var name: String = "Park"
    var age: Int = 15

    func sayNameAndAge() {
        print(name)
        print(age)
    }

    mutating func addAge(amount: Int) {
        age += amount
    }
}

var p1: Human = Human()
p1.addAge(amount: 5)
p1.sayNameAndAge()

/* 결과
Park
20
*/

 

3. 이니셜라이저 요구 (Initializer)

  • 메서드와 마찬가지로 { } 블록은 제외한다.
  • 구조체는 상속이 안되기 때문에 이니셜라이저 요구를 크게 신경 안 써도 됨.
    • 하지만 클래스의 경우에는 이니셜라이저 요구에 부합하는 이니셜라이져 구현 시 required 식별자를 붙여서 프로토콜에서 요구하는 이니셜라이저임을 구분해야한다.
  • 실패 가능한 이니셜라이저 : init?()
    • 구현 시에는 required init?()
import Foundation

protocol Animal {
    var name: String {get set} //읽기, 쓰기 모두 가능
    var age: Int {get set} //읽기만

    init(name: String, age: Int)
    

    func sayNameAndAge()

    mutating func addAge(amount: Int)
}

class Human: Animal {
    var name: String
    var age: Int

    required init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    

    func sayNameAndAge() {
        print(name)
        print(age)
    }

    func addAge(amount: Int) {
        age += amount
    }
}

var p1: Human = Human(name: "Park", age: 15)
p1.addAge(amount: 5)
p1.sayNameAndAge()

/* 결과
Park
20
*/

 

프로토콜의 상속

  • 프로토콜도 하나 이상의 프로토콜을 상속받을 수 있다.
  • 상속은 클래스의 상속 문법과 비슷
  • class 프로토콜을 상속받으면 '클래스 전용 프로토콜'이 된다.

 

선택적 요구

  • 요구사항 중 일부를 선택적 요구사항으로 지정가능
    • 무조건 구현할 필요가 없는 사항들
  • 프로토콜에 @objc 속성을 부여하면 선택적 요구사항 정의 가능
    • Foundation 프레임워크 모듈 임포트 해야함.
  • 선택적 요구사항은 optional 식별자를 정의 앞에 붙여주면 된다.
import Foundation

@objc protocol Animal {
    var name: String {get set} //읽기, 쓰기 모두 가능
    var age: Int {get set} //읽기만

    init(name: String, age: Int)
    

    func sayNameAndAge()

    @objc optional func addAge(amount: Int)
}

class Human: Animal {
    var name: String
    var age: Int

    required init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    

    func sayNameAndAge() {
        print(name)
        print(age)
    }
}

var p1: Human = Human(name: "Park", age: 15)
p1.sayNameAndAge()

/* 결과
Park
20
*/

 

위임을 위한 프로토콜 (Delegate)

  • 위임 (Delegate)
    • 클래스, 구조체가 자신의 임무를 다른 타입의 인스턴스에게 위임하는 디자인 패턴
    • 책무를 위임하기 위해 정의한 프로토콜을 준수하는 타입은 위임된 책무를 할 수 있다는 것을 보장한다.
    • 다른 인스턴스에게 자신이 해야할 일을 맡길 수 있다.
    • 비동기 처리에도 많이 사용된다.
  • 위임 패턴 (Delegate Pattern)
    • 애플 프레임워크에서 사용하는 주요한 패턴
    • EX) UITableViewDelegate 프로토콜 : UITableView의 인스턴스가 해야할 일을 대신 처리하게 함
728x90

'Swift' 카테고리의 다른 글

[Swift] 서브스크립트 (Subscript)  (0) 2021.01.17
[Swift] 접근제어 (Access Control)  (0) 2021.01.17
[Swift] 구조체와 클래스  (0) 2020.12.28
[Swift] 범위 연산자  (0) 2020.12.28
[Swift] 타입캐스팅 (Type casting)  (0) 2020.12.28

댓글