클래스와 상속의 단점
- 하나의 클래스만 상속이 가능함. 즉, 다중 상속 불가능
- 기본적인 상위클래스의 메모리 구조를 따라갈 수 밖에 없음 (필요하지 않은 속성과 메서드도 상속됨)
- 클래스(레퍼런스 타입)에서만 가능
프로토콜
- 위 클래스에만 가능한 상속의 여러 문제를 해결하기 위해 나온 문법
- 실생활에서는 자격증의 개념으로 이해하면 쉬움
- 구체적인 구현을 하지 않음, 요구사항을 정의함. 구체적인 구현은 프로토콜을 채택한 곳에서 구현
- class에서는 상속도 프로토콜도 채택하고 싶은 경우 상속하고자 하는 상위클래스를 먼저쓰고 프로토콜을 적으면 됨
- 상속과 달리 프로토콜은 다중 채택이 가능함으로 ,로 구분해 적으면 됨
protocol CanFly {
func fly()
}
struct Bird: CanFly {
func fly() {
// 구체적인 구현
}
}
class Bird2: AClass, CanFly {
func fly() {
// 구체적인 구현
}
}
프로토콜 속성의 요구사항 정의
- 속성의 뜻에서 var로 선언해야 한다. (let으로 선언할 수 없음)
- get, set 키워드를 통해 읽기/쓰기 여부 설정
- 저장 속성/ 계산 속성 모두 구현 가능
- 최소한의 요구사항을 정확하게 따라서 구현해야함
protocol RemoteMouse {
var id: String { get } // 채택하는 곳에서는 let 저장속성, var 저장속성, 읽기계산속성 / 읽기, 쓰기 계산속성으로 구현가능
var name: String { get set } // 저장속성 / 읽기, 쓰기 계산속성
static var type: String { get set } // 타입 저장 속성 (static) / 타입 계산 속성 (class)
}
struct TV: RemoteMouse {
let id: String = "113"
// var id: String = "113"
// var id: String {
// return "113"
// }
// var id: String {
// get {
// return "113"
// }
// set {}
// }
var name: String = "텔레비젼"
// var name: String {
// get {
// return "텔레비젼"
// }
// set {}
//}
// 타입 저장 속성은 (상속은 되지만) 재정의 원칙적으로 불가능
static var type: String = "리모콘"
// 클래스에서 채택 시 타입 계산 속성에서 class/static 키워드로 모두 구현 가능
// class 키워드는 재정의 가능
// class var type: String {
// get { "리모콘" }
// set {}
// }
}
프로토콜 메서드의 요구사항 정의
1) 메서드 요구사항 정의
- 메서드의 헤드부분(인풋/아웃풋)의 형태만 요구사항으로 정의
- mutating 키워드 : (구조체로 제한하는 것은 아님) 구조체에서 저장 속성 변경하는 경우, 구조체도 채택 가능하도록 허락하는 키워드
- 타입 메서드: 클래스에서 채택 시 static/class 키워드 모두 구현 가능
protocol RandomNumber {
static func reset()
func random() -> Int
}
2) 생성자 요구사항 정의
- 클래스는 (상속을 고려해야함) 생성자 앞에 required를 붙여야 함 (하위에서 구현을 강제)
- 아니면 final을 붙여서 상속을 막으면 required 생략가능
- 클래스에서는 반드시 지정생성자로 구현할 필요없음
3) 서브스크립트 요구사항 정의
- get, set 키워드를 통해서 읽기/쓰기 여부를 설정
- get 키워드 -> 최소한 읽기 서브스크립트 구현 / 읽기, 쓰기 모두 구현 가능
- get, set 키워드 -> 반드시 읽기, 쓰기 모두 구현해야함
protocol DataList {
subscript(idx: Int) -> Int { get }
}
struct DataStructure: DataList {
subscript (idx: Int) -> Int {
// get {
// return 0
// }
return 0
}
}
타입으로써의 프로토콜과 기타 문법
- 스위프트는 프로토콜을 일급객체로 취급함
- 프로토콜은 타입이다
- 프로토콜을 변수에 할당할 수 있음
- 함수를 호출할 때, 프로토콜을 파라미터로 전달할 수 있음
- 함수에서 프로토콜을 반환할 수 있음
- 타입캐스팅을 통해 구체적인 타입으로 사용가능
- 프로토콜 타입으로 저장된 인스턴스를 원래의 타입으로 확인 가능
- 프로토콜 채택 여부 확인 가능
프로토콜의 상속
- 프로토콜 간에 상속이 가능
- 다중 상속이 가능
- 실제 프로토콜의 상속까지 구현할 일은 없지만, 애플이 만들어 놓은 체계에서는 많이 쓰이고 있음
- AnyObject: 클래스 전용 프로토콜
protocol SomeType: AnyObject {
//
}
프로토콜 합성(Protocol Composition) 문법
- 프로토콜을 &로 연결해서, 프로토콜 두개를 병합해서 타입으로 사용하는 것 가능
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
func wishHappyBirthday(to celebrator: Named & Aged) {
//
}
프로토콜의 선택적 요구사항의 구현 (Optional Protocol Requirements)
- 선택적인 멤버선언하기 @objc 키워드 활용
- @objc는 스위프트로 작성한 코드를 오브젝티브C 코드에서도 사용할 수 있게해주는 어트리뷰트
- 프로토콜에서 요구사항 구현 시 반드시 강제해야하는 멤버가 아닌 선택적인 요구사항으로 구현할 때 사용
- @objc 키워드를 붙인 프로토콜은 클래스 전용 프로토콜
- 프로토콜 앞에는 @objc 추가 : objectiveC에서 읽을 수 있는 코드라는 의미
- 멤버 앞에는 @objc optional 추가 : 해당 멤버는 선택적 요구사항으로 바뀜
@objc protocol Remote {
@objc optional var isOn: Bool { get set }
func turnOn()
func turnOff()
@objc optional func doNetflix()
}
어트리뷰트 키워드
- @available, @objc, @escaping, @IBOutlet, @IBAction 등등
- 추가적인 정보를 제공하는 키워드
- 선언에 대한 추가정보 제공 ex) @available
- 타입에 대한 추가정보 제공 ex) @excaping
프로토콜의 확장 (Protocol extension)
- 프로토콜을 채택한 모든 타입에서, 실제 구현을 계속해서 반복적으로 구현하는 불편을 덜기 위해 프로토콜 확장을 제공해 메서드의 기본 구현을 제공해 코드의 중복을 피하는 장점을 얻음
- 단, 해당 프로토콜을 채택해 동일한 메서드를 개발자가 직접 구현하는 경우 개발자가 구현한 메서드가 적용됨
- 프로토콜에 필수 구현으로 적힌 메서드가 아닌 다른 메서드를 확장 시에 정의한다면 해당 프로토콜을 채택 후 동일한 메서드를 개발자가 구현한 경우여도 타입에 따라 해당 메서드가 선택이 되어 실행됨
protocol Remote {
func turnOn()
func turnOff()
}
extension Remote {
func turnOn() { print("리모콘 켜기") }
func turnOff() { print("리모콘 끄기") }
func doAnotherAction() {
print("다른 동작")
}
}
프로토콜 확장의 제한
- where 절을 통해 프로토콜 확장의 적용을 제한할 수 있음
protocol Remote {
func blueOn()
func blueOff()
}
// Remote 프로토콜 타입으로 지정되지 않으면 확장이 적용되지 않음
extension Bluetooth where Self: Remote {
func blueOn() { print("on") }
func blueOff() { print("off") }
}
class SmartPhone: Bluetooth {
// Remote 프로토콜을 채택하지 않아 확장이 적용되지 않음
}
class IPhone: Remote {
// Remote 프로토콜을 채택해 확장이 적용됨
}
추가적으로 알아둬야 할 용어
- Virtual Table 클래스에서의 메서드 테이블
- Witness Table 프로토콜의 메서드 테이블
- Direct dispatch 직접 메모리 주소 삽입
728x90
'FRONT-END > iOS' 카테고리의 다른 글
Swift 중첩 타입 (Nested Types) (0) | 2023.08.02 |
---|---|
Swift Method Dispatch (0) | 2023.08.01 |
Swift 확장(Extensions) (0) | 2023.08.01 |
Swift 타입캐스팅(Type Casting) (0) | 2023.07.31 |
클래스의 상속, 초기화, 생성자 (0) | 2023.07.31 |
댓글