티스토리 뷰
프로토콜........잠깐 뜸했는데요, 프로토콜 마스터를 위해......키키
옛날..?에 프로토콜 (1), (2)를 썼는데요.아직.....1/3도 안했답니다!!!!!!!(충격) 끝까지 따라와주시길 바래요 XD...
Protocols as Types
protocol RandomNumberGenerator {
func random() -> Double
}
저번글에서 RandomNumberGenerator라는 프로토콜을 정의했었죠 :)
굳이 저번글 가셔서 찾아보실 건 없고!!!
우리가 배운 걸 토대로 RandomNumberGenerator라는 프로토콜을 분석해봅시다.
별거 없긴 하지만요 :)......
어떤 특징을 가지고 있죠?
그렇습니다. 딱 하나.
"메소드"를 요구했네요. 즉, 이 프로토콜을 채택하는 타입들은 반드시 저 random이라는 메소드를 구현해야합니다.
잘하셨어요!!
그럼 이제 "타입으로서의 프로토콜"을 봅시다.
protocol RandomNumberGenerator {
func random() -> Double
}
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
print("Random dice roll is \(d6.roll())")
}
Delegation
Adding Protocol Conformance with an Extension
protocol AddString {
var addHello : String { get }
}
자...프로토콜을 하나 만들었어요. get속성만 요구하므로, 모든 종류의 프로퍼티에서 만족시킬 수 있겠네요.
이름에서 보실 수 있겠지만, Hello를 String에 추가시켜주는 프로퍼티입니다.
이제 Extension을 사용해볼텐데요. 이미 원래 있는 타입을 Extension 시켜봅시다.
extension String : AddString{
}
이미 원래 있는 타입인 String을 Extension시켜주고, 우리가 방금 만든 AddString 프로토콜을 채택하게 해주었습니다.
프로토콜을 채택했으니..준수를 해야겠죠? 지금까지는 준수는 하지 않은 상태라
지금 AddString이라는 프로토콜이 addHello라는 프로퍼티를 요구하고있어 ㅎ; 만들어줄래? ㅎ;;;;;;
라고 하죠. 그럼 요구사항을 구현해줘봅시다. 그 전에 주의하셔야 할게 있는데요,
프로토콜 (1)글에서, get만 요구한다. == 모든 종류의 프로퍼티에서 요구사항을 충족시킬 수 있다라고 배웠지만
extension String: AddString{
var addHello: String//error
}
저장 프로퍼티로 만들어버리면 에러가 발생하게 됩니다.
이유는
extensions may not contain stored properties
extension String: AddString{
var addHello: String {
return "Hello \(self)"
}
}
self는 이 addHello를 호출하는 String을 의미합니다.
get이니 리턴만 하면 되겠죠?
이제 사용해볼까요? String타입이기만 하면, 이제 addHello라는 연산프로퍼티를 호출 할 수 있습니다.
짠!!!!
어떤가요 :)
이게 프로토콜의 Extension의 예제로 적절했을지는 모르지만.....아무튼 어떤 느낌??인지는 아시겠죠?!??!
하나만 더 해볼까요?
아 프로토콜 이름...을 어떻게 해야할지 모르겠어서..걍 Zedd프로토콜이라고 만듬 ㅎ
protocol ZeddProtocol {
var returnDouble: Double { get }
mutating func add(n: Int)
}
자.. ZeddProtocol에는 뭐가 있나 봅시다.
먼저 returnDobule이라는 get프로퍼티가 있네요. Double형인것을 보니 Double을 리턴하나봅니다.
아 이번엔 set도 넣어주지 ㅎ; 왜 또 get이에요 ㅎ;;;;;;;
==> 먼저, "연산프로퍼티"에 대해서 아셔야합니다. 연산프로퍼티에서 자기자신에 값을 업데이트하고 자기자신을 리턴할 수 없기 때문에, 저장소를 하나 만들어서 그 저장소의 값을 조작하거나 리턴했죠? 즉 저장소인 저장프로퍼티가 필요합니다.
하지만 지금 extension예제를 하고 있죠? 위에서 잠깐 말씀드렸지만, extension안에서 저장프로퍼티를 만들면 에러가 납니다!!
그러므로 Protocol extension예제에서는 get만 하는걸로 XD
아무튼 계속하겠습니다.
자...그리고 mutating이 나왔네요!!!!!!!mutating은 <Method>에서 배웠죠? 아신다고 가정하고 넘어가겠습니다. 이름이 add이고 파라미터를 받는 걸 보니, 덧셈을 하는 메소드!
그럼 이제 채택해볼까요? Int를 extension해서 ZeddProtocol을 채택해보겠습니다.
extension Int: ZeddProtocol{
var returnDouble: Double{
return Double(self)
}
mutating func add(n: Int) {
self += n
}
}
자..ZeddProtocol이 returnDouble이라는 프로퍼티와 add라는 메소드를 요구하기 때문에 ZeddProtocol을 채택하게된 Int는 returnDouble이라는 프로퍼티와 add라는 메소드를 구현해줘야합니다.
returnDouble은 해당 Int를 Double형으로 리턴하고, add는 지금 자기자신, 즉 현재 Int에 파라미터로 받은 값을 더해주네요.
여기서 mutating을 제거하면 절대 안된다는 것 아시죠? 왜냐하면 Int는 Struct로 구현되어있기 때문입니다 == Value Type이기 때문입니다.
Class와 다르게 말이죠.
자..한번 사용해봅시다.
var number = 10
number.returnDouble//10.0
number.add(n: 20)
number.returnDouble//30.0
짠 XD Protocol의 Extension에 대해서 조금 이해가 가셨나요?
자..그럼 신기한?거 하나만 더 보겠습니다.
struct Zedd {
var myDouble = 0.0
var returnDouble: Double {
return myDouble
}
mutating func add(n: Int) {
myDouble += Double(n)
}
}
자..Zedd라는 Struct를 하나 만들었어요.
그런데 우연히 제가 ZeddProtocol이 요구하는 것들을 이미 다 구현을 했습니다. 하지만, 프로토콜을 채택 안한것. 보이시죠?
그럼 이 Zedd를 extension해서 ZeddProtocol을 채택하도록 하면?
즉,
struct Zedd {
var myDouble = 0.0
var returnDouble: Double {
return myDouble
}
mutating func add(n: Int) {
myDouble += Double(n)
}
}
extension Zedd: ZeddProtocol{
}
이렇게요.
이렇게 하면 에러가 안난답니다!!! 왜냐면 이미 Zedd에서 구현되어 있기때문이죠. 당연하죠???
타입이 이미 프로토콜의 모든 요구사항을 준수하지만, 아직 해당 프로토콜을 채택한다고 명시하지 않은 경우, 빈 extension으로 프로토콜을 채택할 수 있습니다. (you can make it adopt the protocol with an empty extension)
그렇다고 타입이 모든 요구사항을 충족시켰다고 자동으로 프로토콜을 채택하진 않습니다. 항상 프로토콜의 채택을 명시적으로 선언해야합니다.
ㅇㅋㅇㅋ
Collections of Protocol Types
위에서 타입으로서의 프로토콜을 봤었죠? 거기에서 언급한 것처럼, 배열이나 사전과 같은 콜렉션에 저장될 타입으로 프로토콜을 사용할 수 있습니다.
헉 신기..
즉.. 내 프로토콜 타입의 배열 또는 사전을 만들 수 있다는 거에요!!!
var zeddArr = [ZeddProtocol]()
이게 가능하다는 것.
그럼 뭘 넣을 수 있을까요? 위에서 했던 예제들을 생각해봅시다.
var zeddArr = [ZeddProtocol]()
zeddArr.append(0)//[0]
zeddArr.append(1)//[0, 1]
자..이게 가능해지는 것이죠.
헉 왜 Int인 0이랑 1이 들어갈 수 있는거죠?
extension Int: ZeddProtocol {
var returnDouble: Double {
return Double(self)
}
mutating func add(n: Int) {
self += n
}
}
위에서 Int가 ZeddProtocol을 채택하고 준수했으니까 ㅇㅇ
struct Zedd {
var myDouble = 0.0
var returnDouble: Double {
return myDouble
}
mutating func add(n: Int) {
myDouble += Double(n)
}
}
아까 만든 Zedd Struct.
var zedd = Zedd()
이렇게하면 zedd라는 Zedd구조체의 인스턴스가 만들어졌죠?
어 근데 Zedd구조체가 ZeddProtocol을 준수한다?
var zeddArr = [ZeddProtocol]()
zeddArr.append(zedd)
이게 가능해지는 것입니다.
zedd는 Zedd구조체의 프로퍼티에 접근할 수 있죠? 이제?
이렇게요. 그렇다면..
var zeddArr = [ZeddProtocol]()
zeddArr.append(zedd.myDouble)
도 가능할까요?
아쉽게도 아닙니다. 왜냐면 myDouble이라는 애는 Double타입이거든요.
Double이 ZeddProtocol을 따르도록 하지는 않았죠? Zedd라는 구조체가 ZeddProtocol을 따르기때문에, Zedd구조체의 인스턴스만 들어갈 수 있습니다.
"배열이나 사전과 같은 콜렉션에 저장될 타입으로 프로토콜을 사용할 수 있습니다." 이제 이 말이 무슨 소리인지 아시겠죠?
하나만 더 볼게요. 콜렉션에 저장될 수 있다는 것은..................바로바로
var zeddArr = [ZeddProtocol]()
zeddArr.append(0)
zeddArr.append(1)
zeddArr.append(zedd)
for index in zeddArr {
print(index.returnDouble)//0.0 1.0 0.0
}
이렇게 for문을 사용할 수 있게됩니다!!!!! ZeddProtocol타입인 zeddArr에 들어가있다는 말은 ZeddProtocol이 요구하는 returnDouble 프로퍼티를 가진것을 확신할 수 있습니다. 왜 0.0, 1.0, 0.0이 나오는지는 위에서 했던것들을 보시면 아실거에요 :)
Protocol Inheritance
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}
구문은 이렇게 작성하시면 됩니다. 그럼 우리도 한번 사용해봅시다..
protocol ZeddProtocol {
var returnDouble: Double { get }
mutating func add(n: Int)
}
protocol AnotherProtocol { }
protocol InheritingProtocol: ZeddProtocol, AnotherProtocol {
// protocol definition goes here
}
위에서 만든 ZeddProtocol 그냥 쓰겠습니다.
아무튼 InheritingProtocol은 ZeddProtocol과 AnotherProtocol을 상속받고 있습니다.
InheritingProtocol에서 ZeddProtocol이 요구하는거 구현해줘야 하는거 아니에여?
==> InheritingProtocol는 "채택"이 아니라 상속을 받고 있으므로 요구사항 구현 이런거는 안해도 됩니다.
자..위에서 그랬죠? 상속 된 요구사항에 추가로 요구사항을 추가할 수 있습니다. 라고.
그럼 InheritingProtocol에도 뭔가 요구사항을 만들어줘볼게요.
protocol InheritingProtocol: ZeddProtocol, AnotherProtocol {
mutating func sub(n: Int)
}
간단한게 최고. add는 ZeddProtocol에 있으니 빼주는 메소드를 하나 요구해보겠습니다.
자 이제 채택하러 가야겠죠?
protocol InheritingProtocol: ZeddProtocol, AnotherProtocol {
mutating func sub(n: Int)
}
struct Zedd: InheritingProtocol{
//error!
}
저~~기 위에 있던 Zedd 구조체는 잊어버리시고 지금 새로 만드는 겁니다. InheritingProtocol을 채택한 구조체로요.
지금 이상태면 당연히 에러가 날텐데요, 이제 어떻게 에러를 없애야 하는지 감이 오시죠?
네. AnotherProtocol은 아무것도 요구하는 것이 없으니까 그냥 넘어가고,
ZeddProtocol은 returnDouble과 add메소드를 요구하니 이 두개를 구현해줘야겠죠?
그리고!!! InheritingProtocol에서 요구하는 sub도 잊으면 안됩니다.
Zedd 구조체의 코드는
struct Zedd: InheritingProtocol {
var myDouble = 0.0
var returnDouble: Double{
return myDouble
}
mutating func add(n: Int){
myDouble += Double(n)
}
mutating func sub(n: Int) {
myDouble -= Double(n)
}
}
이것이 되겠네요.
뭔가 이제 당연하죠?
오 이제 딱 2/3정도 한거 같아요 :) 다음글이 프로토콜의 마지막 글이 되겠네요!
나름 예제 쉽게 생각한다고 해본건데..XD... 만약 예제에서 틀리거나 지적할 부분이 있다면 꼭!!! 댓글이나 PC화면 오른쪽 하단에 있는 채널 서비스를 이용해서 메세지 주세요 :)
도움이 되었길 바랍니다~~~
'Swift' 카테고리의 다른 글
Swift4 ) Swap / Law of Exclusivity (0) | 2017.12.21 |
---|---|
Swift ) Protocols (4) (3) | 2017.12.17 |
Swift ) Unicode to Int/Int to Unicode (2) | 2017.12.14 |
Swift ) Nested Types (0) | 2017.12.06 |
Swift) dynamic이란? / Realm의 dynamic var는? (8) | 2017.11.17 |
- Swift
- Accessibility
- np-complete
- 스위프트 문법
- fastlane
- np-hard
- swift array
- swift delegate
- swift sort
- WKWebView
- 회고
- swift3
- WidgetKit
- ios 13
- FLUTTER
- WWDC
- Xcode
- iOS delegate
- SwiftUI
- IOS
- swift tutorial
- UIBezierPath
- swift 공부
- Combine
- 스위프트
- 제이슨 파싱
- 피아노
- actor
- github
- Git
- Total
- Today
- Yesterday