Notice
Recent Posts
Recent Comments
Link
大器晩成
[프로토콜] 프로토콜의 확장 (Protocol Extensions) 본문
프로토콜의 확장
- 프로토콜을 채택한 타입에 제공하기 위해서 메서드, 초기화, 서브 스크립트, 연산 프로퍼티들은 확장에서 구현할 수 있습니다.
protocol Bird {
func fly() //Withness Table
func sit()
}
class Eagle: Bird {
}
class Sparrow: Bird {
func fly() {
print("참새가 날고 있습니다.")
}
func hunt() {
print("참새가 사냥 중입니다.")
}
}
extension Bird {
func fly() {
print("새가 날고 있습니다.")
}
func sit() {
print("새가 앉아 있습니다.")
}
func hunt() { //Direct Dispatch
print("새가 사냥 중입니다.")
}
}
let eagle = Eagle()
eagle.fly() //새가 날고 있습니다.
eagle.hunt() // 새가 사냥 중입니다.
let sparrow = Sparrow()
sparrow.fly() //참새가 날고 있습니다.
sparrow.hunt() 참새가 사냥 중입니다.
- 구조체나 클래스에서 직접적으로 구현하지 않더라도, 확장에서 구현한 내용이 구조체나 클래스에서 사용할 수 있습니다.
- "프로토콜 확장"을 제공해서 메서드의 디폴트 구현(기본 메서드)을 제공합니다. (코드의 중복을 피할 수 있습니다.)
[요구사항의 메서드 우선순위 적용] - Witness Table
- 1. (채택) 구현시 해당 메서드 2. 기본 메서드 (확장에서 제공하는 메서드)
[요구사항 메서드의 없을 경우] - Direct Dispath
- 타입이 프로토콜 타입이면, 프로토콜에 정의된 함수를 사용
(프로토콜 / Direct) - 타입이 프로토콜 타입이 아니라면, 자기 클래스 또는 구조체 내의 정된 함수 사용
(구조체 / Direct, 클래스 Virtual table)
프로토콜의 확장을 통한 다영성 제공
- 클래스
protocol Bird {
func fly()
func sit()
}
class Sparrow: Bird {
func fly() {
print("참새가 날고있습니다.")
}
func hunt() {
print("참새가 사냥 중입니다.")
}
}
extension Bird {
func fly() {
print("새가 날고있습니다.")
}
func sit() {
print("새가 앉아있습니다.")
}
func hunt() {
print("새가 사냥중입니다.")
}
}
[Class Virtual 테이블]
- func fly // 참새가 날고 있습니다.
- func sit // 새가 앉아 있습니다.
- func hunt // 참새가 사냥 중입니다.
Sparrow
let sparrow: Sparrow = Sparrow()
sparrow.fly() // V테이블
sparrow.sit() // V테이블
sparrow.hunt() // V테이블
[Protocol Witness 테이블]
- func fly // 참새가 날고 있습니다.
- func sit // 새가 앉아 있습니다.
let sparrow2: Bird = Sparrow()
sparrow2.fly() // 프로토콜 W 테이블
sparrow2.sit() // 프로토콜 W 테이블
sparrow2.hunt() // Direct Dispatch (주소를 직접 전달)
- 구조체
protocol Bird {
func fly()
func sit()
}
struct Eagle: Bird {
func fly() {
print("독수리가 날고있습니다.")
}
func hunt() {
print("독수리가 사냥 중입니다.")
}
}
extension Bird {
func fly() {
print("새가 날고있습니다.")
}
func sit() {
print("새가 앉아있습니다.")
}
func hunt() {
print("새가 사냥중입니다.")
}
}
// 구조체는 메서드 테이블이 없음
let eagle: Eagle = Eagle()
eagle.fly() // (Direct) 직접 메모리 주소 삽입
eagle.sit() // (Direct) 직접 메모리 주소 삽입
eagle.hunt() // (Direct) 직접 메모리 주소 삽입
//독수리가 날고있습니다.
//새가 앉아있습니다.
//독수리가 사냥 중입니다.
let eagle2: Bird = Eagle()
eagle2.fly() // 프로토콜 - W테이블
eagle2.sit() // 프로토콜 - W테이블
eagle2.hunt() // (Direct) 직접 메모리 주소 삽입
//독수리가 날고있습니다.
//새가 앉아있습니다.
//새가 사냥중입니다.
- 프로토콜을 채택한 구조체의 경우, 크기에 따라 Stack 또는 Heap에 저장됩니다.
- String의 경우 구조체여서 Stack에 저장되지만, 엄청 문자열이 길 경우 Heap에 저장될 수도 있습니다.
프로토콜의 확장의 적용 제한
- 프로토콜 확장에서 where절을 통해 프로토콜의 확장의 적용을 제한할 수 있습니다.
- "특정 프로토콜"을 채택한 타입에만 프로토콜 확장이 적용되도록 제한
where Self: 특정 프로토콜 (Self: 타입 자체를 의미) - 특정 프로토콜을 채택하지 않으면, 프로토콜 확장이 적용되지 않습니다.
protocol Bird {
func fly()
func sit()
}
protocol Animals {
func eat()
func sleep()
}
extension Animals where Self: Bird {
func eat() {
print("밥을 먹습니다.")
}
func sleep() {
print("잠을 잡니다")
}
}
//Bird를 채택하지 않으면, eat과 sleep 메서드는 직접 구현해야 합니다.
class Eagle: Animals, Bird {
func sit() {
print("독수리가 앉았습니다.")
}
func fly() {
print("독수리가 날고있습니다.")
}
}
class Eagle2: Animals {
func eat() {
}
func sleep() {
}
func sit() {
print("독수리가 앉았습니다.")
}
func fly() {
print("독수리가 날고있습니다.")
}
}
728x90
'iOS > Swift 문법' 카테고리의 다른 글
self vs Self - [소문자 self] (0) | 2025.02.24 |
---|---|
중첩된 타입 (Nested Types) (0) | 2025.02.24 |
[프로토콜] 선택적 프로토콜 요구사항(Optional Protocol Requirements) (0) | 2025.02.18 |
[프로토콜] 프로토콜의 다중 상속 (0) | 2025.02.18 |
[프로토콜] - 타입으로서 프로토콜 (Protocols as Types) (0) | 2025.02.09 |