1. 프로토콜의 개념
<클래스와 상속의 단점>
하나의 클래스만 상속가능
기본적인 상위클래스의 메모리구조를 따라갈 수 밖에 없음 (필요없는 속성/메서드도 상속됨)
클래스타입에서만 가능
단일상속만 가능
<프로토콜>
간단한 규칙만 따르면 능력을 갖게된다.
다중채택가능
2. 프로토콜의 문법
<문법>
여러개의 프로토콜 채택 가능
1) 정의
protocol MyProtocol {
//요구사항만을 정의
func doing() -> Int
}
메서드의 헤드 부분만 작성
프로토콜을 만들어 필요한 요구사항만을 담음
구체적인구현은 하지 않는다.
2) 채택
class Class: MyProtocol {
}
프로토콜을 체택 (클래스, 구조체, 열거형에서 채택 가능)
3) 구현
class Class: MyProtocol {
func doing() -> Int {
return 7
}
}
프로토콜에서 요구하는 사항을 직접구현
(상속이 있을 경우엔 상속하려는 클래스 먼저 선언 후 프로토콜을 선언해야함)
<요구사항을 정의하는 방법>
1) 속성의 요구사항을 정의
protocol MyProtocol {
var id: String {get}
var name: String {get set}
static var type: String {get set}
}
<인스턴스 속성 요구사항>
최소한의 요구사항을 지정
저장속성/ 계산속성으로 모두 구현 가능(프로토콜 요구사항만으로는 저장/계산속성의 구별 불가
{get} >> 저장속성(var/let) , 계산속성(get,get set)
{get set} >> 저장속성(var), 계산속성(get set)
<타입static속성요구사항>
최소한의 요구사항을 지정
저장타입속성/ 계산타입속성으로 모두 구현 가능
채택시 저장타입속성에서 static키워드로만 구현가능
클래스에서 채택시 static(재정의불가) 또는 class(재정의가능)키워드로 모두 구현 가능
(2)메서드의 요구사항을 정의
<메서드 요구사항>
protocol MyProtocol {
func random() -> Int
mutating func toggle()
static func reset()
}
메서드의 헤드부분을 정의
mutating키워드 >> 구조체에서 저장속성을 변경하는 경우 구조체도 채택가능하도록 허락하는 키워드
타입메서드: 클래스에서 채택시 static/ class키워드로 모두 구현 가능
<생성자 요구사항>
protocol MyProtocol {
init()
subscript(idx: Int) -> Int { get set }
}
생성자를 요구사항으로 지정가능
클래스에서 생성자 채택시, required(필수적)을 붙여야함
클래스가 final로 선언되면 required생략가능
클래스에서는 반드시 지정생성자로 구현할 필요는 없음 (편의생성자로도 구현 가능)
<서브스크립트 요구사항>
최소한의 요구사항을 지정
{get} >> 읽기/읽기쓰기
{get set} >> 읽기쓰기
<상속과 프로토콜 채택의 문법>
extension SomeType: SomeProtocol {
//프로토콜이 원하는 내용 구현
}
관습적으로 프로토콜의 채택은 확장에서 구현하는것을 권장
>> 확장에서 구현한 메서드는 하위클래스에서 재정의되지 않기 때문에
3. 타입으로써의 프로토콜과 기타문법
스위프트는 프로토콜을 일급객체(타입으로사용)로 취급한다.
>>프로토콜을 변수에 할당할 수 있음
>>함수를 호출할때, 프로토콜을 파라미터로 전달할 수 있음
>>함수에서 프로토콜을 반환할 수 있음
프로토콜도 상속이 가능
>>실제 프로토콜의 상속까지 구현할 일은 잘 없음
>>애플이 만들어놓은 체계에서는 많이 쓰이고 있음
프로토콜은 다중상속도 가능함
>>여러가지 요구사항의 나열일 뿐
<클래스전용 프로토콜 (AnyObject)>
protocol SomeType: AnyObject {
//최소한의 요구사항
}
클래스 전용 프로토콜이기 때문에 구조체에선 쓸 수 없다.
<프로토콜의 합성>
let some: AProcotol & BProtocol = (두개의 프로토콜을 모두 채택한 타입의)인스턴스
프로토콜은 &로 연결해서, 프로토콜 두 개를 병합하여 타입으로 사용하는 것 가능
4. 프로토콜의 선택적 요구사항의 구현
<@어트리뷰트 키워드>
컴파일러에게 추가적인 정보를 알려주는 역할
1) 선언에 추가정보 제공
//ios버전 10이상부터 구현된다.
@available(IOs 10.0)
class MyClass {
...
}
2) 타입에 추가정보 제공
func doSomething(completion: @escaping () -> ()) {
...
}
<프로토콜 선택적 요구사항의 구현>
//프로토콜앞엔 @objc
//멤버앞엔 @objc optional
@objc protocol MyProtocol {
var name: Stirng {get}
@objc optional var isOn: Bool {get set} //구현을 해도되고 안해도되고
...
@objc optional func doSomething() //구현을 해도되고 안해도되고
}
선택적 멤버로 선언
프로토콜에서 요구사항 구현시 선택적인 멤버로 구현가능하도록 변형가능
@objc키워드를 프로토콜의 선언앞에 붙여서 추가적인 정보 제공
@objc optional을 멤버앞에 선언 >> 해당 멤버는 선택적 요구사항으로 바뀜
5. 프로토콜의 확장과 프로토콜지향 프로그래밍
프로토콜의 확장은 코드의 중복구현을 피하기 위함
protocol Remote {
func turnOn()
func turnOff()
}
extension Remote {
func turnOn() {print("리모컨 켜기")}
func turnOff() {print("리모컨 끄기")}
func doAnotherAction() {
print("리모컨 또 다른 동작")
}
}
프로토콜을 채택한 타입에서 실제 메서드 구현을 반복(코드 중복 구현)해야하는 불편함 제고/ 단순히 기본구현을 제공하는 개념
<요구사항메서드의 우선순위>
첫째, 구현한 해당 메서드
둘째, >>(구현안했을시) 확장 디폴트 메서드
<프로토콜 지향 프로그래밍>
여러개의 프로토콜 채택가능
메모리 구조에 대한 특정 요구사항 없음
모든 타입에서 채택가능
확장에서 구체적인 정의
6. 프로토콜 확장의 적용제한
//특정 프로토콜을 채택한 타입에만, 프로토콜 확장이 적용
protocol Bluetooth {
func blueOn()
func blueOff()
}
extension Bluetooth where Self: Remote { //리모트프로토콜을 채택한경우에만 확장이 적용됨
func blueOn() {print("블루투스 켜기")}
func blueOff() {print("블루투스 끄기")}
}
프로토콕 확장에서, where절을 통해 프로토콜 확장의 적용을 제한가능
Remote프로토콜을 채택한 타입에만 Bluetooth 프로토콜의 확장이 적용
Remote프로토콜을 채택하지 않은 타입은 Bluetooth프로토콜을 채택가능하지만, 확장은 제공이 안됨 (무조건 직접 구현해야함)
이 포스팅은 인프런 앨런의 스위프트 문법을 기초하여 작성하였습니다. 앨런짱 @@
'swift문법' 카테고리의 다른 글
| [Swift] Part17_중첩타입 (0) | 2022.08.28 |
|---|---|
| [Swift] Part16_메서드 디스패치 (0) | 2022.08.25 |
| [Swift] Part14_확장(Extensions) (0) | 2022.08.23 |
| [Swift] Part13_타입캐스팅(Type Casting) (0) | 2022.08.23 |
| [Swift] Part12_클래스(상속과 초기화) (0) | 2022.08.23 |