Swift의 Protocol — 정의, 문법 및 기능

저자: IT Sectr 게시일: 2026-06-17 읽는 시간: 6 분

Protocol in Swift는 이를 채택하는 모든 타입이 충족해야 하는 요구 사항 집합을 정의하는 계약입니다. 프로토콜은 프로토콜 지향 프로그래밍(POP)의 기초입니다 — Apple이 클래식 OOP와 함께 Swift에 권장하는 패러다임입니다. Apple Documentation, 2026에 따르면, 구조체, 클래스 및 열거형은 프로토콜을 채택할 수 있어 아키텍처를 유연하고 테스트 가능하게 만듭니다.

주요 포인트

  • Protocol — 구조체, 클래스, 열거형을 위한 요구 사항이 있는 계약
  • 요구 사항에는 메서드, 속성, 초기화자 및 서브스크립트가 포함됨
  • Protocol Composition으로 여러 프로토콜을 결합 가능
  • POP — 상속의 대안인 프로토콜 지향 프로그래밍
  • Protocol Extensions은 메서드에 기본 구현을 추가함

Swift에서 Protocol이란?

Protocol은 타입이 무엇을 할 수 있어야 하는지 정의하지만 어떻게 하는지는 정의하지 않는 추상 인터페이스입니다. Swift에서 프로토콜은 Java나 Go의 인터페이스와 유사하지만 추가적인 기능이 있습니다.

프로토콜은 다음을 요구할 수 있습니다:

  • 인스턴스 및 타입 메서드(정적)
  • 속성({ get } 또는 { get set } 지정자 포함)
  • 초기화자
  • 서브스크립트
  • 연관 타입(프로토콜 수준의 제네릭)

WWDC 2015에 따르면, Apple은 프로토콜 지향 프로그래밍을 Swift 애플리케이션 아키텍처의 기본 접근 방식으로 도입했습니다. 클래스 상속이 엄격한 계층 구조를 만드는 OOP와 달리, POP는 프로토콜 합성을 제공합니다. 이는 유연성을 제공합니다: 단일 타입이 여러 프로토콜을 준수할 수 있으며, 확장을 통해 요구 사항과 구현을 얻을 수 있습니다.

프로토콜 선언 문법

Protocol은 키워드 protocol, 이름 및 본문으로 선언됩니다.

swift
protocol Drawable {
    func draw(context: CGContext)
    var boundingBox: CGRect { get }
}

타입은 이름 뒤에 콜론을 사용하여 프로토콜을 채택합니다:

swift
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 }으로 선언됩니다.

swift
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은 다른 프로토콜을 상속하여 새로운 요구 사항을 추가할 수 있습니다. 이는 엄격한 클래스 결합 없이 계약의 계층 구조를 만듭니다.

swift
protocol Vehicle {
    var speed: Double { get set }
    func move()
}

protocol Flyable: Vehicle {
    var altitude: Double { get set }
    func takeOff()
}

Flyable을 채택하는 타입은 두 프로토콜 — VehicleFlyable — 의 요구 사항을 모두 충족해야 합니다. Swift는 프로토콜의 다중 상속을 지원합니다: protocol A: B, C.

Protocol Composition

Protocol Composition은 새로운 결합 프로토콜을 만들지 않고 타입이 동시에 여러 프로토콜을 준수해야 함을 지정할 수 있는 메커니즘입니다.

swift
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은 변수, 함수 매개변수 또는 컬렉션 요소의 타입으로 사용될 수 있습니다. 이를 실존 타입이라고 합니다.

swift
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의 표준 접근 방식입니다.

프로토콜 관련 일반적인 실수

프로토콜 작업 시 개발자들은 종종 몇 가지 반복적인 실수를 저지릅니다.

  • mutating을 잊은 경우 — 프로토콜에서 메서드가 mutating으로 표시되었지만 구조체가 키워드 없이 구현하는 경우
  • 제네릭 대신 프로토콜을 타입으로 사용 — 구체적인 타입이 필요한 곳에 <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. 이는 연관 타입이 없는 프로토콜에서만 작동합니다.

요약

  • Protocol — 메서드, 속성, 초기화자 및 서브스크립트를 위한 계약
  • Class, struct, enum — 모든 타입이 프로토콜을 채택할 수 있음
  • 상속은 엄격한 결합 없이 계약의 계층 구조를 만듦
  • Protocol Composition(&)은 상속 없이 프로토콜을 결합함
  • 실존 타입(any)과 불투명 타입(some) — 프로토콜 작업의 두 가지 방법
  • POP은 Apple이 클래식 클래스 상속의 대안으로 권장함
  • Protocol Extensions으로 기본 구현 추가 가능

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기