Protocol은 프로토콜을 채택하는 타입이 충족해야 하는 요구사항(속성 및 메서드)의 집합입니다. Swift에서 프로토콜은 Protocol-Oriented Programming(POP)의 핵심 요소로, 상속 없이 다형성을 가능하게 합니다. Swift.org(2025)에 따르면 Swift 표준 라이브러리 타입의 85%에서 프로토콜이 사용됩니다. Objective-C에서 @protocol은 비슷한 역할을 하지만 제한이 있습니다 — 클래스만 가능합니다.
핵심 요약
Protocol Swift에서 프로토콜은 타입이 충족해야 하는 요구사항을 정의하는 추상 인터페이스입니다. 프로토콜은 속성(getter/setter 포함), 메서드(인스턴스 및 타입), 초기화자, 서브스크립트를 요구할 수 있습니다. 클래스와 달리 프로토콜은 구조체, 열거형, 클래스에서 채택할 수 있어 순수 클래스 기반 언어에서는 얻을 수 없는 유연성을 제공합니다.
protocol Drawable {
var boundingRect: CGRect { get }
mutating func draw(in context: CGContext)
}
struct Circle: Drawable {
var center: CGPoint
var radius: CGFloat
var boundingRect: CGRect {
CGRect(x: center.x - radius, y: center.y - radius,
width: radius * 2, height: radius * 2)
}
func draw(in context: CGContext) {
context.addEllipse(in: boundingRect)
}
}Circle 구조체는 Drawable 프로토콜을 채택하여 boundingRect 속성과 draw(in:) 메서드를 제공합니다. 프로토콜 덕분에 Drawable을 구현하는 모든 도형을 일관되게 처리할 수 있습니다 — 이는 공통 기본 클래스에서 상속하지 않고 다형성을 구현하는 방법입니다.
Protocol-Oriented Programming(POP)은 Apple이 WWDC 2015에서 클래스 기반 상속의 대안으로 도입한 패러다임입니다. POP에서 프로토콜은 기본 추상화 도구이며 프로토콜 확장은 기본 구현을 제공합니다. 이는 «다이아몬드 상속» 문제를 해결하고 소스 코드를 수정하지 않고도 기존 타입을 확장할 수 있게 합니다.
| 측면 | POP(프로토콜 지향) | OOP(클래스 기반) |
|---|---|---|
| 추상화 단위 | Protocol | 기본 클래스 |
| 재사용 메커니즘 | Protocol extension | 상속 |
| 값 타입 | 지원(struct) | 참조 타입만 |
| 다중 채택 | Protocol composition | 다중 상속(Swift에서는 불가) |
| 결합도 위험 | 낮음(느슨한 결합) | 높음(경직된 계층) |
Apple Swift 블로그(2025)에 따르면 최신 Swift 애플리케이션에서 타입의 70%가 구조체입니다. POP는 이러한 전환의 주요 원인입니다: 프로토콜을 통해 구조체는 클래스로 전환하지 않고도 다형성 동작을 얻을 수 있습니다.
Swift 프로토콜은 Java 인터페이스와 C++ 추상 클래스의 중간 위치를 차지합니다. 구현을 포함할 수 있지만(확장을 통해) 상태(저장 속성)는 가질 수 없습니다. 세 언어의 차이점을 살펴보겠습니다.
| 특성 | Swift Protocol | Java Interface | C++ Abstract Class |
|---|---|---|---|
| 메서드 구현 | 가능(extension) | 가능(default methods) | 가능 |
| 저장 속성 | 불가 | 불가 | 가능 |
| 값 타입 | 가능 | 불가 | 불가 |
| 다중 구현 | 가능 | 가능 | 가능 |
| 초기화자 | 가능(요구사항) | 불가 | 가능 |
주요 차이점: Swift Protocol은 초기화자와 서브스크립트를 요구할 수 있지만 Java Interface에서는 불가능합니다. 그러나 프로토콜은 상태를 저장할 수 없습니다 — 이는 프로토콜을 채택하는 타입의 책임입니다.
Associated Type(연관 타입)은 프로토콜 내부의 제네릭 타입으로, 채택하는 타입에 의해 구체화됩니다. 이를 통해 구체적인 데이터 타입을 지정하지 않고 타입 안전한 프로토콜을 만들 수 있습니다. 연관 타입은 Swift 제네릭과 함께 작동합니다.
protocol Container {
associatedtype Item
var count: Int { get }
mutating func append(_ item: Item)
subscript(i: Int) -> Item { get }
}
struct IntStack: Container {
var items: [Int] = []
var count: Int { items.count }
typealias Item = Int
mutating func append(_ item: Int) {
items.append(item)
}
subscript(i: Int) -> Int {
items[i]
}
}
func sum<C: Container>(_ container: C) -> C.Item where C.Item: Numeric {
// 함수 본문
}Container는 associatedtype Item을 가진 프로토콜입니다. IntStack은 typealias Item = Int를 지정하여 구현합니다. 제네릭 함수 sum은 where 절을 사용하여 숫자 컨테이너에서만 작동합니다. 연관 타입은 타입 안전성을 잃지 않으면서 프로토콜을 제네릭하게 만듭니다.
Protocol composition — & 연산자를 통한 여러 프로토콜의 결합입니다. 컴포지션을 준수하는 타입은 결합된 모든 프로토콜을 구현해야 합니다. 이는 Swift에 없는 다중 상속을 대체하고 함수 매개변수의 요구사항을 정확히 지정할 수 있게 합니다.
protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct Person: Named, Aged {
let name: String
let age: Int
}
func greet(_ entity: Named & Aged) {
print("안녕하세요, \(entity.name), 나이 \(entity.age)!")
}
// Protocol extension — 기본 구현
extension Named {
func introduce() {
print("제 이름은 \(name)입니다")
}
}Protocol extension은 기본 메서드 구현을 제공합니다. 프로토콜을 채택하는 타입은 확장 메서드를 재정의할 수 있으며, 이 경우 자체 구현이 호출됩니다. 이것이 Swift가 @objc 없이 선택적 메서드를 구현하는 메커니즘입니다.
@protocol Objective-C의 @protocol은 Swift Protocol의 전신이지만 중요한 제한이 있습니다. Objective-C 프로토콜은 클래스에서만 사용 가능하며(구조체나 열거형에서는 불가), 메시지 전달을 통한 동적 디스패치를 사용합니다. 메서드는 @required(기본값) 또는 @optional일 수 있습니다.
@protocol Loggable
@required
- (void)logMessage: (NSString *)message;
@optional
- (NSString *)logPrefix;
@end
@interface ConsoleLogger : NSObject
@end
@implementation ConsoleLogger
- (void)logMessage: (NSString *)message {
NSLog(@"[LOG] %@", message);
}
@endSwift와 달리 Objective-C 프로토콜은 연관 타입, 제네릭, 프로토콜 확장 또는 값 타입을 지원하지 않습니다. 이들은 클래스 기반 추상화 메커니즘으로 남아 있는 반면, Swift Protocol은 모든 타입을 위한 완전한 다형성 도구입니다.
자주 묻는 질문
Protocol은 상태(저장 속성)를 저장할 수 없습니다 — 속성 요구사항만 가능합니다. 추상 클래스는 데이터 필드를 포함할 수 있습니다. 프로토콜은 구조체와 열거형에서 채택할 수 있지만, 추상 클래스는 클래스에서만 서브클래싱할 수 있습니다. Swift에서 프로토콜은 기본 추상화 도구이며 클래스는 덜 자주 사용됩니다.
POP는 프로토콜과 프로토콜 확장이 깊은 상속 계층을 대체하는 패러다임입니다. 모든 하위 클래스가 상속하는 기본 클래스 대신, POP는 확장을 통한 기본 구현과 함께 프로토콜 컴포지션을 사용합니다. 이는 결합도를 낮추고 코드 재사용성을 향상시킵니다.
네, Swift 프로토콜은 상속을 지원합니다. protocol SerializableDrawable: Drawable, Codable — Drawable과 Codable의 요구사항을 결합한 프로토콜입니다. SerializableDrawable을 채택하는 타입은 계층 구조의 모든 프로토콜 요구사항을 충족해야 합니다. 이는 클래스 상속과 다릅니다 — 프로토콜에는 공통 조상이 없습니다.
some(불투명 타입)은 함수가 프로토콜을 준수하는 특정 타입을 반환함을 보장합니다. any(실존 타입)는 프로토콜을 준수하는 모든 타입을 저장할 수 있습니다. some은 타입 정체성을 유지하는 데 사용되며, any는 이종 컬렉션에 사용됩니다. some은 Swift 5.1, any는 Swift 5.7에서 도입되었습니다.
확인에는 is를, 캐스팅에는 as?를 사용합니다: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. Objective-C에서는 conformsToProtocol:을 사용합니다. Swift는 연관 타입이 없는 프로토콜에 대한 is 확인도 지원합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.