Protocol in Swift는 이를 채택하는 모든 타입이 충족해야 하는 요구 사항 집합을 정의하는 계약입니다. 프로토콜은 프로토콜 지향 프로그래밍(POP)의 기초입니다 — Apple이 클래식 OOP와 함께 Swift에 권장하는 패러다임입니다. Apple Documentation, 2026에 따르면, 구조체, 클래스 및 열거형은 프로토콜을 채택할 수 있어 아키텍처를 유연하고 테스트 가능하게 만듭니다.
주요 포인트
Protocol은 타입이 무엇을 할 수 있어야 하는지 정의하지만 어떻게 하는지는 정의하지 않는 추상 인터페이스입니다. Swift에서 프로토콜은 Java나 Go의 인터페이스와 유사하지만 추가적인 기능이 있습니다.
프로토콜은 다음을 요구할 수 있습니다:
{ get } 또는 { get set } 지정자 포함)WWDC 2015에 따르면, Apple은 프로토콜 지향 프로그래밍을 Swift 애플리케이션 아키텍처의 기본 접근 방식으로 도입했습니다. 클래스 상속이 엄격한 계층 구조를 만드는 OOP와 달리, POP는 프로토콜 합성을 제공합니다. 이는 유연성을 제공합니다: 단일 타입이 여러 프로토콜을 준수할 수 있으며, 확장을 통해 요구 사항과 구현을 얻을 수 있습니다.
Protocol은 키워드 protocol, 이름 및 본문으로 선언됩니다.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
타입은 이름 뒤에 콜론을 사용하여 프로토콜을 채택합니다:
struct Circle: Drawable {
let center: CGPoint
let radius: CGFloat
func draw(context: CGContext) {
context.addArc(center: center, radius: radius, ...)
}
var boundingBox: CGRect {
CGRect(x: center.x - radius, y: center.y - radius,
width: radius * 2, height: radius * 2)
}
}
단일 타입은 쉼표로 구분하여 여러 프로토콜을 채택할 수 있습니다: struct MyType: ProtocolA, ProtocolB. 컴파일러는 각 프로토콜의 모든 요구 사항이 충족되었는지 확인합니다.
속성 요구 사항은 키워드 var와 접근 지정자 { get } 또는 { get set }으로 선언됩니다.
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
프로토콜에서 키워드 mutating은 메서드가 self를 수정할 수 있음을 나타냅니다. 구조체는 이러한 메서드를 mutating으로 구현해야 하지만, 클래스는 생략할 수 있습니다. 메서드 요구 사항은 매개변수 레이블을 포함한 전체 시그니처로 선언됩니다.
Protocol은 다른 프로토콜을 상속하여 새로운 요구 사항을 추가할 수 있습니다. 이는 엄격한 클래스 결합 없이 계약의 계층 구조를 만듭니다.
protocol Vehicle {
var speed: Double { get set }
func move()
}
protocol Flyable: Vehicle {
var altitude: Double { get set }
func takeOff()
}
Flyable을 채택하는 타입은 두 프로토콜 — Vehicle 및 Flyable — 의 요구 사항을 모두 충족해야 합니다. Swift는 프로토콜의 다중 상속을 지원합니다: protocol A: B, C.
Protocol Composition은 새로운 결합 프로토콜을 만들지 않고 타입이 동시에 여러 프로토콜을 준수해야 함을 지정할 수 있는 메커니즘입니다.
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
합성(&)은 함수 매개변수, 변수 및 제네릭 제약 조건에서 작동합니다. 컴파일러는 전달된 타입이 동시에 모든 프로토콜을 충족하는지 확인합니다. 합성은 SwiftUI에서 널리 사용됩니다: some View는 합성을 가진 제네릭입니다.
Protocol Composition은 상속 계층 구조를 만드는 것보다 선호됩니다: protocol A: B, C 대신 직접 B & C를 채택할 수 있습니다. 이는 유연성을 제공하고 결합을 줄입니다. 합성은 중간 프로토콜을 만들지 않고 일시적으로 요구 사항을 결합해야 하는 함수 매개변수 및 제네릭 제약 조건에서 특히 유용합니다. 이는 코드에서 보조 타입의 수를 줄입니다.
Protocol은 변수, 함수 매개변수 또는 컬렉션 요소의 타입으로 사용될 수 있습니다. 이를 실존 타입이라고 합니다.
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]
func process(drawables: [any Drawable]) {
for item in drawables {
item.draw(context: ...)
}
}
키워드 any(Swift 5.6+)는 명시적으로 실존 타입을 표시합니다. any가 없으면 컴파일러가 경고를 표시합니다. Swift는 프로토콜 뒤에 구체적인 타입을 숨기기 위한 some(불투명 타입)도 지원합니다 — 이는 SwiftUI의 표준 접근 방식입니다.
프로토콜 작업 시 개발자들은 종종 몇 가지 반복적인 실수를 저지릅니다.
<T: Drawable> 대신 Drawable을 사용하는 경우AnyObject를 사용하여 구조체와 열거형을 제외하는 경우자주 묻는 질문
Protocol은 구현 없이 요구 사항만 정의합니다(protocol extensions 이전까지). 추상 클래스는 구현과 상태를 포함할 수 있습니다. Swift에는 추상 클래스가 없습니다 — 그 역할은 확장이 있는 프로토콜이 수행합니다.
네, 구조체, 클래스 및 열거형 모두 프로토콜을 채택할 수 있습니다. 이것이 POP의 기초입니다: 아키텍처를 구성하기 위해 클래스를 사용할 필요가 없습니다. 프로토콜이 있는 구조체는 값 의미론과 불변성을 제공합니다.
연관 타입(associatedtype)은 구현하는 타입이 스스로 결정하는 타입의 자리 표시자입니다. 예: Collection에는 associatedtype Element가 있습니다. 이는 프로토콜 수준의 제네릭입니다.
네, AnyObject에서 상속을 추가하세요: protocol MyProtocol: AnyObject. 그러면 클래스만 이 프로토콜을 채택할 수 있습니다. 약한 참조와 델리게이트에 유용합니다.
확인에는 is를, 캐스팅에는 as?를 사용하세요: if let drawable = item as? Drawable. 이는 연관 타입이 없는 프로토콜에서만 작동합니다.
요약
&)은 상속 없이 프로토콜을 결합함any)과 불투명 타입(some) — 프로토콜 작업의 두 가지 방법턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.