大器晩成

[프로토콜] - 타입으로서 프로토콜 (Protocols as Types) 본문

iOS/Swift 문법

[프로토콜] - 타입으로서 프로토콜 (Protocols as Types)

zerobugpark 2025. 2. 9. 21:23

 

스위프트에서 프로토콜은 일급객체이기 때문에, 타입으로 사용할 수 있습니다. 

* 프로토콜은 타입입니다.

protocol Bird {
    func fly()
    func sit()
}

struct Eagle: Bird {
    func fly() {
        print("독수리가 날고있습니다.")
    }
    
    func sit() {
        print("독수리가 앉아있습니다.")
    }
    
    func hunt() {
        print("독수리가 사냥 중입니다.")
    }
    
}

struct Sparrow: Bird {
    func fly() {
        print("참새가 날고있습니다.")
    }
    
    func sit() {
        print("참새가 앉아있습니다.")
    }
    
}


let eagle: Bird = Eagle()
eagle.fly() // 독수리가 날고있습니다.
eagle.sit() // 독수리가 앉아있습니다.
(eagle as? Eagle)?.hunt() // 독수리가 사냥 중입니다.


let sparrow: Bird = Sparrow()
sparrow.fly() // 참새가 날고있습니다.
sparrow.sit() // 참새가 앉아있습니다.
  • 구조체 타입이 아닌 채택하고 있는 프토콜을 타입으로 저장할 수 있습니다.
  • 이때 프토콜에서 정의된 메서드만 사용이 가능합니다.
  • eagle는  Bird타입이기 때문에, hunt 메서드는 실행할 수 없습니다. 
  • 다운 캐스팅을 통해 동일한 타입으로 변경하게 되면, 구조체의 타입으로 변경되기 때문에, 구조체 내에 정의한 함수도 사용이 가능합니다.

 

타입으로서 프로토콜의 장점

// 1. 프로토콜 타입 취급의 장점 
// 서로 다른 타입을 담을 수 있다.
let species: [Bird] = [eagle, sparrow]

for bird in species {
    bird.fly()
}

// 2. 프로토콜 타입 취급의 장점 
// 함수의 파리미터 타입으로 사용이 가능
func flySomeBirds(bird: Bird) {
    bird.fly()
}

flySomeBirds(bird: eagle)
flySomeBirds(bird: sparrow)
  • 서로 다른 타입이어도 동일한 프로토콜을 채택하고 있다면, 같은 타입으로 취급할 수 있습니다. (Any가 아니어도 됨)
  • 함수 파라미터의 타입으로도 사용이 가능합니다.

프로토콜 준수성 검사

  • is 연산자: 특정 타입이 프로토콜을 채택하고 있는지 확인 (참 또는 거짓) // 인스턴스 확인도 가능
  • as 연산자: 타입 캐스팅 (특정 인스턴스를 프토콜로 변환하거나, 프로토콜을 인스턴스 실제 형식으로 다운 캐스팅)
// 1) is 연산자
// 특정 타입이 프로토콜 프로토콜 채택 여부
eagle is Bird
sparrow is Bird


// 프로토콜로 저장된 인스턴스의 구체적인 타입 확인
let species: [Bird] = [eagle, sparrow]

species[0] is Eagle
species[1] is Sparrow


// 2) as 연산자
// as: 업캐스팅
let upEagle = eagle as Bird
upEagle.fly()
upEagle.sit()


// as :다운 캐스팅
let downEagle = species[0] as? Eagle
downEagle?.fly()
downEagle?.sit()
downEagle?.hunt()
  • 프로토콜이 더 범용적인 타입이기 때문에, 프로토콜 타입으로 변환하는 것은 업캐스팅입니다.
  • 프로토콜 타입을 구체적인 타입으로 변환하는 것은 다운캐스팅입니다.
728x90