일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 네이버 치지직
- Swift 기능
- StateObject
- 앱 비교 프로젝트
- 제앱소
- react
- sqoop
- global soop
- 애플 디벨로퍼 아카데미
- apple developer academy 후기
- Swift 디자인패턴
- 데이터베이스 공부
- Swift 문법
- 네이버 부스트캠프
- useReducer
- 치지직
- 애플 디벨로퍼 아카데미 21주차 회고
- iOS 개발 오류
- 데이터베이스
- SWIFT
- 애플 아카데미 후기
- Apple Developer Academy @ POSTECH
- 소프트웨어분석및설계
- ObservableObject
- ObservedObject
- 운영체제
- 애플 디벨로퍼 아카데미 후기
- swift문법
- OS
- 숭실대
- Today
- Total
사과하는 제라스
[Swift 지식] Swift에서 프로토콜이 클래스를 상속한다고? 본문
목차
서론
안녕하세요! 라스입니다~!👋🏻🤖👋🏻
(라디오 스타 아닙니다.)
제가 이번주에 P.O.P(Protocol Oriented Programming)에 대한 포스팅을 쓰고 있었는데요...
D.D.D(the Deadly Diamond of Death)를 공부하면서 코드를 짜보다가 이상함을 발견했습니다.
바로... 프로토콜이 클래스를 상속할 수 있다는 것입니다..!!
Java 과외를 할 때 interface는 class를 상속하지 못한다고 그렇게 강조를 하던 제라스인데...
'엥? 프로토콜이 클래스 원래 상속 못하지 않나???' 라는 생각이 확확 들더라구요!
그래서 P.O.P 포스팅은 던져두고 이 포스팅을 쓰게 되었습니다.
그럼 오늘도 한번 시작해보겠습니다~!
아니 뭔 프로토콜이 클래스를 상속해...?
네... 가능하다고 합니다.
class Class_example1 {
func hello1_1() -> Void {
print("hello1")
}
}
이런 클래스가 있다고 할 때
protocol ProtocolExtendsClass: Class_example1 {
}
이렇게 프로토콜이 클래스를 상속이 가능합니다.
저는 이렇게 쓰는 순간 Error를 띄워주겠지...? 했는데 아니더라구요 ㅎㅎ
그럼 일단 이 프로토콜을 가지고 클래스를 구현해볼까? 해서 다음과 같이 A 클래스가 ProtocolExtendsClass를 구현하도록 했습니다.
// 'ProtocolExtendsClass' requires that 'A' inherit from 'Class_example1'
// Type 'A' does not conform to protocol 'ProtocolExtendsClass'
class A: ProtocolExtendsClass {
func foo() {
print("hi")
}
}
그랬더니 위처럼 2개의 Error가 떴습니다.
종합적인 이유는 하나로 'A 클래스가 Class_example1을 상속하지 않고 있다'는 것입니다.
그래서 이걸 구현하려면... Class_example1을 상속하고 있든가, Class_example1을 상속하는 서브클래스를 상속하고 있으면 됩니다.
다음과 같이요...!
class Class_example1 {
func hello1_1() -> Void {
print("hello1")
}
}
class Subclass_example1: Class_example1 {
}
class A: Class_example1, ProtocolExtendsClass {
func foo() {
print("hi")
}
}
class B: Subclass_example1, ProtocolExtendsClass {
func foo() {
print("hi")
}
}
이렇게 하면 Error 없이 잘 구현이 됩니다.
사실 이건 상속이 아니라 채택이다
죄송합니다. 사실 상속 아닙니다. 상속처럼 생겼지만 사실 상속이 아닙니다.
https://twitter.com/johnsundell/status/1110491386636308480?lang=en
이 분의 말씀으로는 상속이라고 하시지만 제 나름에서는 이건 상속이 아니라고 결론을 내렸습니다.
제가 생각한 괜찮은 단어는 '채택 제한'인 것 같습니다.
구글링 선생님과 함께 고민을 많이 해봤는데 그 과정을 천천히 풀어보겠습니다.🥹🥹
https://stackoverflow.com/questions/58852513/protocol-inheritance-from-class
위 링크의 스오플을 보면서 UIKit을 쓸 때 어떻게 했는지 생각해보면 어떤 기본 컴포넌트(ex. UIView)만이 채택할 수 있도록 하고 싶을 때 쓰는 방식이기도 했습니다. 마치 다음처럼요.
protocol Pressable: UIView {
func funcUsedInUIView()
}
이게 사실 Swift5 Release note를 참고해보면
Swift4에서는 다음과 같이 써서 해당 프로토콜을 채택할 수 있는 타입을 강제했었는데,
protocol Pressable {
}
// UIView 타입(서브클래스 포함)만이 사용가능한 Pressable extension
extension Pressable where Self: UIView {
func funcUsedInUIView() {}
}
근데 이렇게 쓸 때 다음과 같은 문제들이 발생하기에,
Swift5에서는 나름 개선된 방식(그렇다고 이렇게만 쓸 수 있는 건 아니고 기존 방식도 가능합니다.)으로 다음과 같이 프로토콜이 클래스를 상속(사실 상속 아닙니다! 모양이 그렇다는 겁니다ㅎㅎ정확히는 채택이 맞습니다.)하는 형태가 가능해졌습니다. 근데 이건 상속이 아니라 채택 타입에 대한 제한 정도로 생각하는게 맞다고 봅니다.
프로토콜이 상속(?)하는 클래스에 대한 구현부를 갖고 있는 건 아니니까요!
다음과 같은 상황을 봅시다!
class Class_example1 {
func hello1_1() -> Void {
print("응~클래스의 hello1_1이야")
}
}
protocol ProtocolExtendsClass: Class_example1 {
}
extension ProtocolExtendsClass {
func hello1_1() -> Void {
print("응~프로토콜의 hello1_1이야")
}
}
class A: Class_example1, ProtocolExtendsClass {
}
A().hello1_1() // 응~클래스의 hello1_1이야
이렇게 프로토콜의 것이 아닌 자기 자신의 타입인 Class_example1의 함수가 실행이 되어버립니다.
하나 더 보자면,
class Class_example1 {
func hello1_1() -> Void {
print("응~ 나 class의 hello1_1이야~")
}
}
protocol ProtocolExtendsClass: Class_example1 {
}
extension ProtocolExtendsClass {
override func hello1_1() -> Void {
print("응~ 나 Class_example1의 hello1_1 오버라이드했어~") // Method does not override any method from its parent protocol
}
}
이렇게 상속을 했는데 오버라이드가 안된다?? 이건 상속이 아닌겁니다.
그럼 이런 거 왜 씀?
제가 제일 궁금했던 부분입니다...!!ㅎㅎ
일단 결론을 내린 부분은 '해당 클래스의 타입을 가진 클래스만 이 프로토콜을 구현할 수 있다'를 표현해두기 위함이라고 두었습니다.
즉, 우리가 흔히 아는 프로토콜을 채택하는 타입 혹은 클래스에 대한 제한입니다.
쓰임1. 클래스 타입으로의 제한
Swift5에서는 Class-Only Protocol. 이렇게 표현하기도 합니다.
위처럼 AnyObject로 두면은 오직 클래스들만 이 프로토콜을 채택할 수 있습니다. 예전에는 사실 다음과 같이 class를 써도 무방했다고 합니다. 꽤 이 부분에 대한 논쟁이 있었다고 아래 블로그를 뒤적뒤적 하다가 알게되었습니다.ㅎㅎㅎ
https://zeddios.tistory.com/508
쓰임2.
처음에 예시로 보여드린 방식입니다.
class Class_example1 {
func hello1_1() -> Void {
print("hello1")
}
}
protocol ProtocolExtendsClass: Class_example1 {
}
class A: Class_example1, ProtocolExtendsClass {
}
즉, 클래스냐 구조체냐의 타입이 아닌 정말 새로 만든 클래스들 그 자체로 타입을 가져가는 방식입니다.
이건 사실 아직 사용해보진 않은 방식이라 그런지 어색하긴 합니다.
어디서 쓸 수 있을지...도 사실 아직 감이 안 잡히긴 합니다.
혹시 아시는 분이 계시다면 댓글로 조언 부탁드립니다!
마무리
오늘은 Swift에서 Protocol의 class에 대한 상속같은 채택 제한 기능을 살펴봤습니다.
뭔가 제목이 참 어그로 끌릴 것 같긴한데 사실 큰 별거는 없었던 느낌이 조금은 드네요.
그래도 이렇게 AnyObject를 활용해서 Class-Only 프로토콜을 만들 수 있을 뿐만 아니라 어떤 클래스로의 채택을 제한하는 데에 있어서도 쓰일 수 있단 점을 알게 되어서 좋았던 것 같습니다 ㅎㅎ
🙇🏻♂️ 오늘도 긴 포스팅 읽어주셔서 감사합니다! 🙇🏻♂️
곧, 정말 조만간 P.O.P와 관련된 포스팅으로 돌아오겠습니다!
참고
https://stackoverflow.com/questions/58852513/protocol-inheritance-from-class
https://twitter.com/johnsundell/status/1110491386636308480?lang=en
https://github.com/apple/swift/issues/48153
https://zeddios.tistory.com/508
아직 꼬꼬마 개발자입니다.
더 나은 설명이나 코드가 있다면 언제든 환영입니다.
적극적인 조언과 피드백 부탁드립니다!
그럼 오늘도 개발 가득한 하루되세요!
- Xerath -
🤖🤖🤖🤖🤖🤖🤖
'제라스의 iOS 공부 > Swift 지식' 카테고리의 다른 글
[Swift 지식] UITableView Cell의 생명주기(feat.prefetch를 써보자!) (0) | 2024.05.10 |
---|---|
[Swift 지식] @ObservedObject vs @StateObject 이 둘 언제 쓰는데? (feat.Observation) - (24.06.07 업데이트) (0) | 2024.05.05 |
[Swift 지식] @Bindable 딥다이브(였던 것) feat. 사실 Observable 딥다이브... (3) | 2024.04.07 |
[Swift 지식] removeAll(keepingCapacity: Bool)의 성능 비교 (1) | 2024.03.14 |
[Swift 지식] Single Source Of Truth(SSOT)란? (0) | 2024.03.12 |