swift문법

[Swift] Part15_프로토콜

화찌님 2022. 8. 24. 23:50

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프로토콜을 채택가능하지만, 확장은 제공이 안됨 (무조건 직접 구현해야함)

 


이 포스팅은 인프런 앨런의 스위프트 문법을 기초하여 작성하였습니다. 앨런짱 @@