관리 메뉴

사과하는 제라스

[Swift 지식] Swift에서 프로토콜이 클래스를 상속한다고? 본문

제라스의 iOS 공부/Swift 지식

[Swift 지식] Swift에서 프로토콜이 클래스를 상속한다고?

Xerath(제라스) 2024. 3. 31. 00:08

목차

    728x90
    반응형

    서론

    안녕하세요! 라스입니다~!👋🏻🤖👋🏻

    (라디오 스타 아닙니다.)

     

    제가 이번주에 P.O.P(Protocol Oriented Programming)에 대한 포스팅을 쓰고 있었는데요...

    D.D.D(the Deadly Diamond of Death)를 공부하면서 코드를 짜보다가 이상함을 발견했습니다.

     

    바로... 프로토콜이 클래스를 상속할 수 있다는 것입니다..!!

     

    Java 과외를 할 때 interface는 class를 상속하지 못한다고 그렇게 강조를 하던 제라스인데...

    '엥? 프로토콜이 클래스 원래 상속 못하지 않나???' 라는 생각이 확확 들더라구요!

     

    그래서 P.O.P 포스팅은 던져두고 이 포스팅을 쓰게 되었습니다.

    포스팅 ADHD 제라스

    그럼 오늘도 한번 시작해보겠습니다~!

     

    아니 뭔 프로토콜이 클래스를 상속해...?

    네... 가능하다고 합니다.

    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

     

    John Sundell (@johnsundell) on X

    New in Swift 5: Protocols can now "inherit" from classes - requiring all types conforming to that protocol to also inherit from the specified class 👍 I'll be posting a LOT more Swift 5 content over the next weeks & months - and also update previous arti

    twitter.com

    이 분의 말씀으로는 상속이라고 하시지만 제 나름에서는 이건 상속이 아니라고 결론을 내렸습니다.

     

    제가 생각한 괜찮은 단어는 '채택 제한'인 것 같습니다.

    구글링 선생님과 함께 고민을 많이 해봤는데 그 과정을 천천히 풀어보겠습니다.🥹🥹

     

    https://stackoverflow.com/questions/58852513/protocol-inheritance-from-class

     

    Protocol inheritance from class?

    I read the documentation about Protocols and can't find any information about protocol inheriting from a class, but the code compiles. As far as I remember protocols can only inherit other protocol...

    stackoverflow.com

    위 링크의 스오플을 보면서 UIKit을 쓸 때 어떻게 했는지 생각해보면 어떤 기본 컴포넌트(ex. UIView)만이 채택할 수 있도록 하고 싶을 때 쓰는 방식이기도 했습니다. 마치 다음처럼요.

    protocol Pressable: UIView {
        func funcUsedInUIView()
    }

     

    이게 사실 Swift5 Release note를 참고해보면

    Swift4에서는 다음과 같이 써서 해당 프로토콜을 채택할 수 있는 타입을 강제했었는데,

    protocol Pressable {
    }
    
    // UIView 타입(서브클래스 포함)만이 사용가능한 Pressable extension
    extension Pressable where Self: UIView {
        func funcUsedInUIView() {}
    }

     

    근데 이렇게 쓸 때 다음과 같은 문제들이 발생하기에,

    Apple 공식 GitHub 참고:  https://github.com/apple/swift/issues/48153

     

    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. 이렇게 표현하기도 합니다.

    참고: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols/#Class-Only-Protocols

     

    위처럼 AnyObject로 두면은 오직 클래스들만 이 프로토콜을 채택할 수 있습니다. 예전에는 사실 다음과 같이 class를 써도 무방했다고 합니다. 꽤 이 부분에 대한 논쟁이 있었다고 아래 블로그를 뒤적뒤적 하다가 알게되었습니다.ㅎㅎㅎ

    https://zeddios.tistory.com/508

     

    Swift ) Class only Protocol. class? AnyObject?

    안녕하세요 :) Zedd입니다.글을 읽다가문득..class와 AnyObject의 차이점을 알고싶어졌습니다. 위 사진은 한마디로, 프로토콜이 클래스타입에서만 채택되고 싶다! 하면 프로토콜 선언부에 AnyObject를

    zeddios.tistory.com

     

    쓰임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

     

    Protocol inheritance from class?

    I read the documentation about Protocols and can't find any information about protocol inheriting from a class, but the code compiles. As far as I remember protocols can only inherit other protocol...

    stackoverflow.com

    https://twitter.com/johnsundell/status/1110491386636308480?lang=en

     

    John Sundell (@johnsundell) on X

    New in Swift 5: Protocols can now "inherit" from classes - requiring all types conforming to that protocol to also inherit from the specified class 👍 I'll be posting a LOT more Swift 5 content over the next weeks & months - and also update previous arti

    twitter.com

    https://github.com/apple/swift/issues/48153

     

    [SR-5581] Proper support for protocol 'where' clause with constraints on 'Self' · Issue #48153 · apple/swift

    Previous ID SR-5581 Radar rdar://problem/38077232 Original Reporter rayfix (JIRA User) Type Bug Status Resolved Resolution Done Environment Xcode Version 9.0 beta 4 (9M189t), Playground, MacBook Pr...

    github.com

    https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols/#Class-Only-Protocols

     

    Documentation

     

    docs.swift.org

    https://zeddios.tistory.com/508

     

    Swift ) Class only Protocol. class? AnyObject?

    안녕하세요 :) Zedd입니다.글을 읽다가문득..class와 AnyObject의 차이점을 알고싶어졌습니다. 위 사진은 한마디로, 프로토콜이 클래스타입에서만 채택되고 싶다! 하면 프로토콜 선언부에 AnyObject를

    zeddios.tistory.com

     

     

     

     

     


    아직 꼬꼬마 개발자입니다.

    더 나은 설명이나 코드가 있다면 언제든 환영입니다.

    적극적인 조언과 피드백 부탁드립니다!

     

    그럼 오늘도 개발 가득한 하루되세요!

    - Xerath -

    🤖🤖🤖🤖🤖🤖🤖

     

    728x90
    반응형