Swift) Protocol 이해하기 (2/6) - 프로퍼티 / 메서드 선언 이해하기
안녕하세요!? 소들입니다 ☘️
저번 포스팅에서 프로토콜이 무엇인지에 대해 간단하게 공부했잖아요!?!?!
이번엔 이 프로토콜을 프로퍼티, 메서드로 선언할 때의
여러 가지 특징(?)에 대해 공부를 해보려고 해요!!!
모든 포스팅은 편의 말투로 합니다~!!
1. 프로토콜에서 프로퍼티 선언하기
protocol Band {
var drum: String { get set }
var vocal: String { get set }
var piano: String { get set }
var guitar: String { get set }
}
|
위처럼 Band라는 것에 대해 일종의 약속, 즉 프로토콜을 만들었잖음?
앞으로 밴드는 이러이러한 속성(보컬, 피아노, 드럼, 기타)는 꼭 필요해요!! 하고!!
위처럼 필요한 속성에 대해 프로토콜 내부에 프로퍼티로 선언을 해두는데,
이때으 ㅣ특징에 대해 알아보겠음
일단 프로퍼티가 4개나 되어 넘 많우ㄴㅣ..........
피아노 프로퍼티 1개로 살펴 봅시다
1-1. 프로토콜을 채택해서 선언된 프로퍼티를 구현할 경우, 저장 프로퍼티로 구현하든, 연산 프로퍼티로 구현하든 상관 없다
우리가 쉽게 오해할 수 있는 것 중 하나가,
프로토콜에 선언되어 있는 프로퍼티는 항상 저장 프로퍼티로 구현해야 한다!! 인데,
class ABand: Band {
var piano: String = "sodeul" // piano 프로퍼티를 저장 프로퍼티로 정의
}
class BBand: Band {
var piano: String { // piano 프로퍼티를 연산 프로퍼티로 정의
return "sodeul"
}
}
|
위처럼 Band라는 프로토콜에 선언되어 있는 같은 piano 프로퍼티를 구현하더라도,
저장 프로퍼티 / 연산 프로퍼티와 상관 없이 구현할 수 있음!
1-2. 프로토콜에 선언되는 프로퍼티는 항상 var로 선언 되어야 한다
protocol Band {
var piano: String { get set }
}
|
잠깐 다시 프로토콜 선언으로 돌아가서 보자면,
위처럼 프로토콜 내에 프로퍼티를 선언할 땐 반드시
var로 선언해주어야 함!!!
만약 let으로 선언해주면,
이렇게 에러가 뜨면서 var로 바꾸라고 나옴!!!!
프로토콜의 프로퍼티는 채택하는 곳에서 저장 / 연산 상관없이 구현 가능한데,
이때 연산 프로퍼티는 반드시 var로 선언해야 하기 때문에 (연산 프로퍼티의 경우 let 선언 자체가 불가)
만약 프로토콜에서 let으로 선언해두면, 구현하는 곳에서 연산 프로퍼티로 사용할 수 없어,
var가 필수로 요구되는 것이 아닐까 싶음(에러 메서지 내용도 그렇고!!)
에엥 그러면 해당 프로토콜을 채택하는 곳에선 항상
프로토콜에 선언된 프로퍼티를 var로 선언해야 하나요??
라는 의문이 들 수 이씀니다
이 질문에 대한 답은 바로바로!!!!!!!!!!!
연산 프로퍼티는 당연히 var로 선언해야 된다! (let은 원래 불가하다 닝겐!)
그러나 저장 프로퍼티의 경우, 타입 뒤에 달려 있는 { get set }에 따라 달려있다!
입니다 XD
이해가 안 갈테니 이해를 하러 가봅시다!
1-3. { get set } 속성에 따라 달라지는 let / var 속성
여러어부운
{ get set }의 속성에 대해 알아봅시다아
근데, 머라거??
저장 프로퍼티는 { get set }에 따라서 let / var의 속성이 달라질 수 있습니다
근데 연산 프로퍼티는 오로지 var만 가능하기 때문에 var만 사용해야 됩니다
를 이해 했다면 매우 쉬움ㅋ
1️⃣ { get }
저장 프로퍼티의 경우 let / var선언 모두 가능 합니다
연산 프로퍼티의 경우 getter(get-only) / getter & setter 선언 모두 가능 합니다
protocol Band {
var piano: String { get }
}
|
위처럼 get으로 선언할 경우,
실제 채택하는 곳에서 저장 프로퍼티로 구현할 경우
let, var로 선언하든 상관 없음!!! 둘 다 가넝!!!
class ABand: Band {
let piano: String = "sodeul"
}
class BBand: Band {
var piano: String = "sodeul"
}
|
이렇게, let으로 선언해도 / var로 선언해도 문제 없단 말임!!
연산 프로퍼티로 구현할 경우,
class ABand: Band {
var random: String = ""
var piano: String {
get {
return "sodeul"
}
}
}
class BBand: Band {
var random: String = ""
var piano: String {
get {
return "sodeul"
}
set {
self.random = newValue
}
}
}
|
위처럼 getter만 만들어서 get-only로 만들어도,
getter setter모두 만들어서 둘 다 사용하든 문제 없음!!!
2️⃣ { get set }
저장 프로퍼티의 경우 var로만 선언 가능합니다
연산 프로퍼티의 경우 getter & setter로 선언해주어야 합니다
protocol Band {
var piano: String { get set }
}
|
위처럼 프로토콜 선언부의 프로퍼티를 { get set }으로 해줄 경우,
실제 채택하는 곳에서 저장 프로퍼티로 구현할 경우
무조건 var로만 선언할 수 있고, let으로는 선언할 수 없음
class ABand: Band {
let piano: String = "sodeul" // error! Type 'ABand' does not conform to protocol 'Band'
}
class BBand: Band {
var piano: String = "sodeul"
}
|
위처럼 저장 프로퍼티를 let으로 선언할 경우, Band 프로토콜을 따르고 있지 않다고 에러가 남!
따라서 { get set } 으로 선언 될 경우, 반드시 구현하는 쪽에서 저장 프로퍼티는 var로 선언 해주어야 함!
연산 프로퍼티로 구현할 때도 마찬가지로,
class ABand: Band {
var random: String = ""
var piano: String { // error! Type 'ABand' does not conform to protocol 'Band'
get {
return "sodeul"
}
}
}
class BBand: Band {
var random: String = ""
var piano: String {
get {
return "sodeul"
}
set {
self.random = newValue
}
}
}
|
{ get set } 일 경우, getter setter 모두 제공하는 것이 필수임!
따라서 위처럼 getter만 제공하는 경우(get-only), 에러가 발생함! setter만들어! 라는 ㅎ;ㅎ;;
1-4. 어떤 프로퍼티는 opional로 설정하고 싶은데요
하면 이전 포스팅에서 말했듯이
@objc protocol Band {
var piano: String { get set }
@objc optional var base: String { get set }
}
|
이렇게 @objc를 붙여서 @optional로 선언해주면
채택해주는 곳에서 꼭 선언해주지 않아도 에러가 안 남
2. 프로토콜에서 메서드 선언하기
protocol Band {
func play() }
|
프로토콜에서 메서드의경우,
함수의 헤더 부분만 위처럼 작성해두고,
바디 부분은 해당 프로토콜을 채택하는 곳에서 직접 구현해야 된다고 했잖음!??!
class ABand: Band {
func play() {
print("ABand!")
}
}
|
이런 식으루!!! 메서드의 선언은 매우 간단함 :)
아.. 근디
함수의 헤더 부분을 프로토콜의 선언해 둔다는 게 조금 어렵게 와닿을 수 있는데..
함수 타입 선언임니까...? 함수 표기법임니까...? 먼디요..? 싶을 수 읶ㅆ는디..
그냥.... 우리 그냥 메서드 선언할 때 있잖음..? 그때 { } 이거 뺀 부분 선언하는 것임...
이렇게..ㅎ_ㅎ...
어렵게 생각하지 마셈 ㅎ_ㅎ..
2-1. 구조체의 경우, mutating이 필요하면 프로토콜 자체에 추가
만약, 구조체의 경우 메서드 안에서 프로퍼티 값을 변경해야 할 경우
반드시 mutating이란 키워드를 func 앞에 붙여줘야 하잖음??
이때는, mutating도 같이 프로토콜에 선언해주면 됨!!
protocol Renameable {
mutating func changeName(newName: String)
}
struct Sodeul: Renameable {
var name: String = "sodeul"
mutating func changeName(newName: String) {
self.name = newName
}
}
class DeulSo: Renameable {
var name: String = "sodeul"
func changeName(newName: String) {
self.name = newName
}
}
|
이렇게!!
이때 위처럼 프로토콜 메서드 자체에 mutating이 붙어 있는 경우,
구조체의 경우는 반드시 changeName이란 메서드를 선언할 때 mutating을 붙여야 하고,
클래스의 경우엔 mutating 키워드가 필요 없으니 떼고 선언해 주면 됨!!!
(위 코드에서 구조체의 경우 mutating이 붙지 않을 경우, 아예 다른 함수로 인식하기 때문에 에러가 뜸)
.
.
.
후움.. 생각보다 길어져서 생각보다 포스팅이 늦어졌네요 ㅠ_ㅠ...
만약 잘못된 내용이나 오타 및 피드백 댓글 주세요!!!