반응형
LinkedIn 개발자로 성장하면서 남긴 발자취들을 확인하실 수 있습니다.
Github WWDC Student Challenge 및 Cherish, Tiramisul 등 개발한 앱들의 코드를 확인하실 수 있습니다.
개인 앱 : Cherish 내 마음을 들여다보는 시간, 체리시는 디자이너와 PM과 함께 진행 중인 1인 개발 프로젝트입니다.
10년 후, 20년 후 나는 어떤 스토리 텔러가 되어 있을지 궁금하다. 내가 만약에 아직 조금 더 탐구하고 싶은 게 있고, 궁금한 게 있다면, 그게 설사 지금 당장의 내 인생에 도움이 안 되는 것 같더라도 경험해보자. 그 경험들을 온전히 즐기며 내 것으로 만들고, 내 일에 녹여내고... 그러다보면 그 점들이 모여 나란 사람을 그려내는 선이 될 테니까.

Recent Posts
Recent Comments
Total
관리 메뉴

꿈꾸는리버리

protocol 정복기 ( 1 / 3) 본문

오뚝이 개발자/swift

protocol 정복기 ( 1 / 3)

rriver2 2022. 7. 24. 01:07
반응형

protocol.. 얇게 알았었던 protocol에 대해 이번 기회에 좀 더 깊게 공부해서 정리를 해보고자한다 !

 

🌷 protocol이란?  

protocol은 특정 역할을 하기 위한 메소드, 프로퍼티, 기타 요구사항 등의 청사진(설계도)를 의미한다. 구조체, 클래스, 열거형은 정의된 프로토콜을 채택해서 특정 기능을 실행하기 위한 프로토콜의 요구사항을 직접 구현해야 한다. 이렇게 프로토콜의 요구사항을 모두 따르는 타입은 해당 프로토콜을 준수한다고 표현한다. 

-> 무슨 소리인가 싶은데,, 쉽게 말해서 "해당 protocol을 따르기 위해서는 protocol에 적혀있는 사항들을 모두 이행해야 한다" 라고 생각하면 이해하기 편하다. 그래서 처음배울때 "protocol == 약속"이라고 생각하세요~ 하는 거다.

 

protocol에서는 정의하고 제시하기만 할 뿐이고 구현체에는 해당 protocol을 따르는 타입에서 실제로 구현이 된다.

 

 예시 코드 

protocol 프로토콜A이름 {
	프로토콜A정의
}

class 클래스이름: 프로토콜A이름 {
	프로토콜A요구사항 이행
    
    이외의 코드들...
}

위 코드에서  클래스는 프로토콜A을 채택했기 때문에 프로토콜A의 요구사항들을 모두 이행해야 한다. 

 

다음과 같이 여러개의 protocol을 상속 받을 수도 있다!

class 클래스이름: 프로토콜A, 프로토콜B, 프로토콜C {
	프로토콜A,B,C 요구사항 이행
    
    이외의 코드들...
}

 

이때 주의 사항이 struct와 enum과 달리 class는 "상속"이 있다는 것이다.

( 이후에도 계속 class의 상속 때문에 다른 점들이 언급될 것임 ..)

 

class에서는 상속도 다음과 같이 : 뒤에 표기했잖슴..? 그래서 뭐지.. 하면서 따로 표기하는 방법이 있나? 했는데

class 클래스이름: 부모클래스 {
    클래스 정의
}

그게 아니라 슈퍼 클래스의 이름을 제일 좌측에 선언하고, 그 다음 프로토콜들을 나열해서 이어적기만 하면 된다 !

 예시 코드 

class 클래스이름: 부모클래스, 프로토콜A, 프로토콜B {
	프로토콜A,B 요구사항 이행
    클래스 정의
}

-> 부모클래스를 상속 받았으며, 프로토콜A,B를 채택한 클래스이다.

 


이제 좀 더 자세하게 프로토콜에 대해 알아보도록 하자.

 

🌷 protocol 요구사항 

protocol을 채택하게 되면, protocol이 요구하는 기능들을 해당 타입(struct, enum, class)가 따라야 한다고 했었다.

그리고 이때 protocol이 요구하는 기능에는 프로퍼티나, 메소드 등의 기능을 의미한다.

 

1️⃣ property 요구

protocol은 자신을 채택한 타입이 어떤 property를 구현해야 하는지 요구가 가능하다. 

1) 이때 property의 종류 즉, computed property인지 stored property인지에 대해서는 밝힐 필요가 없지만,  해당 property를 읽기 전용으로 할지 혹은 읽기와 쓰기 모두 가능하게 할지는 정해줘야 한다.

읽기 전용 property는 property 정의 뒤에 { get }을, 읽기와 쓰기 모두 가능한 property는 property 정의 뒤에 { get set }을 명시해야 한다. ( 쓰기 전용 property는 원래 없음 )

근데 생각해보면, get set 을 명시해 둠으로 property의 종류도 어느정도 제한을 두게 된다.

예를 들어, property가 읽고 쓰기가 가능한 프로퍼티를 요구시에는 구현체에는 상수 stored property나 읽기 전용 computed property는 구현할 수 없게 된다.

 

 예시 코드 

protocol 프로토콜A {
    var 프로퍼티a:Int { get } // 읽기가 가능한 프로퍼티a
    var 프로퍼티b: Int { get set } //읽고 쓰기가 모두 가능한 프로퍼티b
}

 

2) 그리고 프로퍼티에서는 항상 var 키워드를 이용해야 하고 구현체에선 var 과 let 모두 사용할 수 있다. 

 

3) 프로토콜에서 { get } 프로퍼티는 구현부에서  { get  set } 프로퍼티로 구현할 수 있지만, { get  set }  프로퍼티는 { get }  프로퍼티로 구현할 수 없다. 

 

무슨 이야기인지.. 윗 글을 읽고 이해하지 못해도 괜찮다.. 이제 한번 ! 코드로 알아봐 보자 !

 

🌷 { get } 읽기 전용의 property를 요구하는 경우

protocol FullName {
    var firstName: String { get }
}

1) FullName 프로토콜은 읽기 전용의 firstName의 property을 요구한다.

 

2) 프로퍼티에서는 항상 var 키워드를 이용해야 하기 때문에 var로 작성했다.

+ 구현체에선 var 과 let 모두 사용할 수 있다.

-> 다음과 같이 구현체에서는 get이라는 조건에 맞추면 되기 때문에 let과 var 둘 다로 기능을 구현할 수 있다.

// 1. 변수(variable) 저장 프로퍼티
class PersonA: FullName {
    var firstName: String
    init(firstName: String) {
        self.firstName = firstName
    }
}

// 2. 상수(constant) 저장 프로퍼티
class PersonB: FullName {
    let firstName: String
    init(firstName: String) {
        self.firstName = firstName
    }
}

 

3) 프로토콜에서 읽기 전용 프로퍼티는 구현부에서 읽고 쓰기가 모두 가능한 프로퍼티로 구현할 수 있다.

-> 이렇게 { get } property를 요구할 때는 { get } 뿐만이 아니라 { get set }도 가능하다.

//3. 연산프로퍼티 - gettable
class PersonC: FullName {
    var name: String
    var firstName: String {
        name
    }
    init(name: String) {
        self.name = name
    }
}

//4. 연산프로퍼티 - gettable/settable
class PersonD: FullName {
    var name: String
    var firstName: String {
        get {
            return name
        }
        set {
            name = newValue
        }
    }
    init(name: String) {
        self.name = name
    }
}

 

🌷 { get set }  읽기와 쓰기 전용의 property를 요구하는 경우

protocol FullName {
    var firstName: String { get set }
}

-> FullName은 이제 읽고 쓰기 전용의 property인 firstName을 요구한다.

 

따라서 firstName은 구현체에서 상수 stored property(let)나 읽기 전용 computed property(get)는 구현할 수 없게 된다.

// 1. 변수(variable) 저장 프로퍼티
class PersonA: FullName {
    var firstName: String
    init(firstName: String) {
        self.firstName = firstName
    }
}

// 2. 상수(constant) 저장 프로퍼티 
// -> 프로토콜을 따르지 않았다는 에러 발생
// class PersonB: FullName {
//     let firstName: String
//     init(firstName: String) {
//         self.firstName = firstName
//     }
// }
// 3. 연산프로퍼티 - gettable
// -> 프로토콜을 따르지 않았다는 에러 발생
// class PersonC: FullName {
//     var name: String
//     var firstName: String {
//         name
//     }
//     init(name: String) {
//         self.name = name
//     }
// }

//4. 연산프로퍼티 - gettable/settable
class PersonD: FullName {
    var name: String
    var firstName: String {
        get {
            return name
        }
        set {
            name = newValue
        }
    }
    init(name: String) {
        self.name = name
    }
}

 

4) 타입 property

클래스의 타입 프로퍼티에는 상속 가능한 타입의 프로퍼티인 class type property와 상속이 불가능한 static type property가 있는데, 만약 프로토콜에서 타입 프로퍼티를 요구하고 싶다면, 두 경우 모두 static 키워드를 사용하면 된다.

protocol FullName {
    static var firstName: String { get }
    static var lastName: String { get set }
}

 -> 이후 구현부에서 class나 static에 맞게 골라서 구현하면 된다.

 

 


 

이번 포스팅에서는 protocol이 무엇인지와 protocol에서 property를 요구할 때 주의해야 하는 사항들에 대해서 알아봤다.

다음 포스팅에서는 protocol에서 method나 init을 요구할 때에 대해 알아보고자 한다 !

 

  참조  

https://docs.swift.org/swift-book/LanguageGuide/Protocols.html

 

Protocols — The Swift Programming Language (Swift 5.7)

Protocols A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of tho

docs.swift.org

 

 

 

반응형
Comments