Warning: 이해한 부분을 최대한 남기고 정리하려 남긴 글 입니다. 틀린 부분이 있을 수 있습니다. 이점 유의하고 읽어주시면 감사할 것 같습니다. 그리고 틀린 부분 알려주시면 바로바로 고치도록 하겠습니다.
협의된 규약, 규정?!?
스위프트의 규약, 규정 또는 약속!!
그리고 객체들이 소통하는 창구라 볼 수 있다
예시: 아이언맨이라고 규정한 우리의 약속
↓↓ 아래와 같은 특징을 가져야 아이언맨이라 부를 수 있다.
protocol IronMan {
func fly()
func call()
func 비상탈출()
var weapon: String { get }
var color: UIColor { get }
}
struct MarkI: IronMan {
func fly() {
<#code#>
}
func call() {
<#code#>
}
func 비상탈출() {
print("씽씽 난다.")
}
var weapon: String
var color: UIColor = .black
}
struct MarkII: IronMan {
func fly() {
<#code#>
}
func call() {
<#code#>
}
func 비상탈출() {
print("빨리빨리 난다.")
}
var weapon: String
var color: UIColor = .red
}
프로토콜은 특정 기능 수행에 필수적인 요소 를 정의하는 청사진[blueprint]이다.
프로토콜을 만족시키는 타입[Type] 은 우리는 해당 타입이 프로토콜을 따른다[conform]고 말합니다.
프로토콜에 필수 구현을 추가하거나 추가적인 기능을 더하기 위해 프로토콜을 확장[extend]하는 것이 가능합니다.
MarkI과 MarkII 모두에게 출동 명령을 내려야 하는데 이를 메서드로 표현하면...
func 출동명령(누구에게: MarkI) {
}
func 출동명령2(누구에게: MarkI) {
}
위와 같이 MarkI 그리고 Mark II 둘 다에게 같은 명령의 메서드를 두 개나 불필요하게 만들어줘야 한다.
그런데 프로토콜을 사용하면 위와 같은 불필요한 상황을 피할 수 있습니다.
func 출동명령(누구에게: IronMan) {
}
let 마크1 = MarkI()
let 마크2 = MarkII()
출동명령(누구에게: 마크2)
출동명령(누구에게: 마크1)
위와 같이 메서드 하나만 생성한 뒤 MarkI과 MarkII가 채택한 프로토콜을 출동명령의 parameter 타입으로 지정 해 주면 해당 메서드를 마크1과 마크2 둘다 공유할 수 있습니다.
프로토콜의 정의는 클래스, 구조체, 열거형과 유사합니다.
protocol SomeProtocol {
// protocol definition goes here
}
해당 프로토콜을 따르는 타입인 경우 아래와 같이 적습니다.
struct SomeStructure: SomeProtocol {
// structure definition goes here
}
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
static var someTypeProperty: Int { get set }
}
프로토콜에서는 저장된 프로퍼티인지 저장 프로퍼티인지 명시하지 않는다!
명시해야 하는 것:
프로퍼티의 이름
프로퍼티의 타입
그리고 해당 프로퍼티가 gettable한지 settable한지
타입 프로퍼티는 static
키워드를 적어서 선언한다
protocol FullyNamed {
var fullName: String { get }
}
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// ncc1701.fullName is "USS Enterprise"
FullyNamed
는 하나의 프로퍼티를 갖고 있는 프로토콜이다.
이 프로토콜을 따르는 Starship
이라는 구조체를 선언하면 프로토콜에 저장된 fullName
프로퍼티를 사용할 수 있고 위와 같이 computed property
로 사용될 수 있다.
메소드 파라미터의 기본 값은 프로토콜 안에서 사용할 수 없습니다.
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 }}let generator = LinearCongruentialGenerator()print("Here's a random number: \(generator.random())")// Prints "Here's a random number: 0.3746499199817101"print("And another one: \(generator.random())")// Prints "And another one: 0.729023776863283"
위 코드는 프로토콜의 필수 메소드 random()
을 구현한 클래스입니다.
MobileDevice
타입을 Device protocol
을 채택하여 구현하였습니다.
protocol Device { var brand: String { get } var name: String { get } func turnOn() func turnOff()}class MobileDevice: Device { var brand: String var name: String init(brand: String, name: String) { self.brand = brand self.name = name } func turnOn() { print("기기가 켜졌습니다") } func turnOff() { print("기기가 꺼졌습니다.") }}
protocol Togglable { mutating func toggle()}enum OnOffSwitch: Togglable { case off, on mutating func toggle() { switch self { case .off: self = .on case .on: self = .off } }}var lightSwitch = OnOffSwitch.offlightSwitch.toggle()// lightSwitch is now equal to .on
Togglable
프로토콜을 따르는 OnOffSwitch
에서 toggle()
메소드를 가져와서 해당 열거형의 내부를 변경할 수 있습니다.
다시한 번 아이언맨 예시를 한 번 들어보자
protocol 비서능력 { func 검색(무엇: String) -> String func 운전(목적지: String)}protocol 비서능력 { func 검색(무엇: String) -> String func 운전(목적지: String)}struct 자비스: 비서능력 { func 검색(무엇: String) -> String { return "\(무엇)이 구글 검색 결과 입니다." } func 운전(목적지: String) { print("운전합니다.") } }struct 포츠: 비서능력 { func 검색(무엇: String) -> String { return "\(무엇) 좀 그만 검색해요" } func 운전(목적지: String) { print("운전시작") }struct CEO { var 비서: 비서능력?}
나의 권한과 할일을 위임 - Delegate
= Delegation Pattern
현실토니스타크가 어떤 이벤트가 일어났을 때 비서에게 일을 맡긴다는 것이 프로토콜이라는 협의체로 이뤄져있다. 비서공고를 할 떄 나는 특정한 능력이 필요하고 어떤 이벤트가 일어난 경우 어떻게 대응해야 하는지 이러한 요구을 적어 놓은 공고모집서를 현실세계 프로토콜의 delegation방식이 구현되어있다라고 볼 수 있다.