스위프트 프로토콜 vs 클래스 상속: 유연한 기능 구현을 위한 최적의 선택
스위프트에서 프로토콜은 특정 역할을 수행하기 위한 메서드, 프로퍼티, 기타 요구사항 등을 정의하는 청사진이다. 클래스, 구조체, 열거형은 이러한 프로토콜을 채택(Adopt)하여 실제로 기능을 구현할 수 있다.
단, 프로토콜은 클래스를 상속하지 않고, 요구사항을 정의만 하며 구현은 직접 하지 않는다. 즉, 프로토콜은 다른 언어에서 말하는 인터페이스와 유사하지만, 스위프트에서는 그들만큼 강력한 구현을 요구하지 않는다(:
1. 프로토콜 정의 및 요구사항
protocol Talkable {
var topic: String { get set } // 주제에 대한 프로퍼티 (읽고 쓸 수 있어야 함)
var language: String { get } // 언어에 대한 프로퍼티 (읽기만 가능)
func talk() // 말하는 메서드 (구현이 아니라 정의만)
}
- topic: 어떤 주제에 대해 말할지를 정의하는 변수이다. 읽고 쓸 수 있어야 하므로 get set으로 정의된다.
- language: 어떤 언어로 말할지를 정의하는 변수이다. 읽기만 가능하므로 get으로만 정의된다.
- talk(): 말을 한다는 메서드를 정의한다. 이 메서드는 구현을 요구하지 않는다.
결론적으로, 프로토콜은 "기능의 청사진"을 제공하고, 실제로 구현하는 것은 이를 채택한 구조체, 클래스, 또는 열거형이 담당한다.
2. 프로토콜 채택 및 구현
struct Person: Talkable {
var topic: String
let language: String
func talk() {
print("\(topic)에 대해 \(language)로 말합니다")
}
init(topic: String, language: String) {
self.topic = topic
self.language = language
}
}
- Person 구조체는 Talkable 프로토콜을 채택하고 있다.
- topic과 language 프로퍼티를 구현하고, talk() 메서드를 구현하여 프로토콜의 요구사항을 만족시킨다.
- init() 이니셜라이저를 통해 Person을 생성할 수 있다.
3. 프로토콜 상속 및 다중 프로토콜 채택
스위프트에서는 프로토콜 상속을 통해 여러 프로토콜을 결합하거나 더 많은 요구사항을 추가할 수 있다.
protocol Readable {
func read()
}
protocol Writeable {
func write()
}
protocol ReadSpeakable: Readable, Writeable {
func speak()
}
struct Book: ReadSpeakable {
func read() {
print("Reading the book")
}
func write() {
print("Writing the book")
}
func speak() {
print("Speaking about the book")
}
}
- Readable과 Writeable 프로토콜을 상속한 ReadSpeakable 프로토콜을 정의했다.
- Book 구조체는 ReadSpeakable 프로토콜을 채택하고, read(), write(), speak() 메서드를 모두 구현한다.
- 스위프트에서는 다중 상속이 가능하여 여러 프로토콜을 동시에 채택할 수 있다.
4. is와 as?를 이용한 프로토콜 준수 확인
스위프트에서는 is와 as? 연산자를 사용하여 인스턴스가 특정 프로토콜을 준수하는지 확인할 수 있다.
let book: Book = Book()
var someAny: Any = book
// `is` 연산자: 객체가 특정 프로토콜을 준수하는지 확인
print(someAny is Readable) // true, book은 Readable을 준수
print(someAny is Writeable) // true, book은 Writeable을 준수
print(someAny is ReadSpeakable) // true, book은 ReadSpeakable을 준수
// `as?` 연산자: 객체를 안전하게 캐스팅하여 해당 프로토콜로 변환
if let readable = someAny as? Readable {
readable.read() // "Reading the book" 출력
}
if let writeable = someAny as? Writeable {
writeable.write() // "Writing the book" 출력
}
if let speakable = someAny as? ReadSpeakable {
speakable.speak() // "Speaking about the book" 출력
}
- is 연산자: 객체가 특정 프로토콜을 준수하는지 확인한다. 예를 들어, someAny is Readable은 someAny가 Readable을 준수하는지 검사한다.
- as? 연산자: 객체를 특정 프로토콜 타입으로 안전하게 캐스팅하려고 시도한다. 타입 캐스팅이 성공하면 해당 타입의 메서드나 프로퍼티를 사용할 수 있다.
5. 프로토콜의 한계와 클래스 상속과의 차이점
- 프로토콜은 구현을 제공하지 않고 단지 요구사항을 정의한다. 클래스나 구조체에서 프로토콜을 채택한 후 구현을 해야 한다.
- 클래스는 상속을 통해 기능을 확장할 수 있고, 프로토콜은 다중 채택을 통해 여러 가지 기능을 동시에 가져올 수 있다.
인터페이스와 프로토콜의 차이점:
- 인터페이스는 기본적으로 모든 메서드가 추상적이며, 기본 구현이 제공되지 않는다.
- 프로토콜은 메서드의 구현을 요구하지 않으며, 다중 채택이 가능하고, 구조체, 클래스, 열거형 모두 채택할 수 있다.
스위프트의 프로토콜은 클래스 상속과 다르게 구현을 요구하지 않고, 기능을 정의하는 역할을 한다. 프로토콜을 채택한 타입이 해당 기능을 구현하는 방식으로 동작한다. 클래스 상속은 하나의 부모 클래스를 상속받지만, 프로토콜은 다중 채택을 할 수 있어 더욱 유연하다. 프로토콜을 타입으로 사용할 수 있어, 여러 타입을 처리하는 데 유용하며, 동적 디스패치를 활용할 수 있는 것!(:
반응형
'IT' 카테고리의 다른 글
Swift 오류처리 : 자판기 예제로 배우는 throw, throws, try, do-catch, switch-case, defer (0) | 2025.05.21 |
---|---|
Swift 익스텐션 활용법: 연산 프로퍼티, 메서드, 서브스크립트 추가하기 (0) | 2025.05.14 |
Swift : assert, guard, 그리고 제어 흐름 제어문 (0) | 2025.05.11 |
Swift에서 is와 as로 배우는 타입 확인과 변환의 핵심 (0) | 2025.05.11 |
Swift 옵셔널 체이닝과 nil 병합 연산자 (0) | 2025.05.11 |
댓글
이 글 공유하기
다른 글
-
Swift 오류처리 : 자판기 예제로 배우는 throw, throws, try, do-catch, switch-case, defer
Swift 오류처리 : 자판기 예제로 배우는 throw, throws, try, do-catch, switch-case, defer
2025.05.21 -
Swift 익스텐션 활용법: 연산 프로퍼티, 메서드, 서브스크립트 추가하기
Swift 익스텐션 활용법: 연산 프로퍼티, 메서드, 서브스크립트 추가하기
2025.05.14 -
Swift : assert, guard, 그리고 제어 흐름 제어문
Swift : assert, guard, 그리고 제어 흐름 제어문
2025.05.11 -
Swift에서 is와 as로 배우는 타입 확인과 변환의 핵심
Swift에서 is와 as로 배우는 타입 확인과 변환의 핵심
2025.05.11