티스토리 뷰
프로토콜은 특정 기능 수행에 필수적인 요소를 정의한 Blueprint의 개념이다. 프로토콜을 만족시키는 타입을 프로토콜을 따른다(conform)고 말한다. 프로토콜에 필수 구현을 추하가하거나 추가적인 기능을 더하기 위해 프로토콜을 확장하는 것 또한 가능하다.
Java의 인터페이스를 implements 하는 개념과 비슷하다고 생각할 수도 있겠다.
문법부터 차근차근 알아보자.
1. 프로토콜 문법
프로토콜의 정의는 클래스, 구조체, 열거형 등과 유사하다.
protocol SomeProtocol {
// protocol definition goes here
}
프로토콜을 따르는 타입을 정의하기 위해서는 타입 이름 뒤에 콜론을 붙이고 Conforming 할 프로토콜 이름을 적는다.
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
부모클래스를 상속 받는 경우 아래와 같이 상속할 클래스를 앞에 적는다.
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// class definition goes here
}
2. 프로퍼티 요구사항
프로토콜에서는 프로퍼티가 저장된 프로퍼티인지 계산된 프로퍼티인지 명시하지 않는다. 하지만 프로퍼티의 이름과 타입, 그리고 gettable, settable인지는 명시해야 한다.
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
타입 프로퍼티는 static키워드와 함께 선언한다.
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
이제 하나의 프로퍼티를 갖는 프로토콜을 하나 선언한 뒤에 이를 따르는 구조체를 하나 선언하여 사용해보자.
protocol FullyNamed {
var fullName: String {get}
}
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Applesed")
또한 아래와 같이 fullName 프로퍼티를 계산된 프로퍼티로 재정의하여 사용할 수 있다.
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")
3. 메서드 요구사항
마찬가지로 필수 인스턴스 메서드와 타입 메서드를 명시할 수 있다. 하지만 메서드 파라미터의 기본 값은 프로토콜 안에서 사용할 수 없다.
필수 메서드 지정 시 함수명과 반환 값을 지정할 수 있고, 구현에 사용하는 괄호는 적지 않아도 된다.
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"
4. 변경 가능한 메서드 요구사항
mutating 키워드를 사용하여 인스턴스에서 변경 가능하다는 것을 표시할 수 있다. class 타입은 레퍼런스 타입이기 때문에 굳이 mutating 없이도 값 변경이 가능하다.
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.off
lightSwitch.toggle()
// lightSwitch is now equal to .on
5. 이니셜라이저 요구사항
마찬가지로 프로토콜에서 필수로 구현해야 하는 이니셜라이저를 지정할 수 있다.
단, 프로토콜에서 init을 필수로 구현하도록 선언했기 때문에 이를 따르는 클래스에서 생성자를 선언할 때는 반드시 required 키워드를 붙여야 한다.
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}
6. 타입으로써의 프로토콜
프로토콜도 하나의 타입으로 사용되기 때문에 다음과 같이 허용되는 모든 곳에 프로토콜을 사용할 수 있다.
1) 함수, 메서드, 이니셜라이저의 파라미터 타입 혹은 리턴 타입
2) 상수, 변수, 프로퍼티의 타입
3) 컨테이너인 배열, 사전 등의 아이템 타입
다음은 프로토콜을 타입으로 사용한 예제이다.
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())")
}
// Random dice roll is 3
// Random dice roll is 5
// Random dice roll is 4
// Random dice roll is 5
// Random dice roll is 4
7. 프로토콜 타입 콜렉션
프로토콜을 Array, Dictionary등 Collection 타입에 넣기위한 타입으로 사용할 수 있다. 아래는 TextRepresentable 프로토콜을 따르는 객체 Array에 대한 선언이다.
let things: [TextRepresentable] = [game, d12, simonTheHamster]
for thing in things {
print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon
8. 프로토콜 상속
클래스 상속과 동일하게 프로토콜 또한 상속할 수 있다.
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// protocol definition goes here
}
이 외에도 프로토콜 위임이나 익스텐션 등 여러 응요 문법이 존재하지만 꽤나 복잡한 예제를 다루고 있기도 하고, 아직 익스텐션을 다루지 않기 때문에 이 포스팅에서도 따로 다루지 않고 넘어가려고 한다.
프로토콜에 대한 자세한 레퍼런스는 아래에서 확인할 수 있다.
https://jusung.gitbook.io/the-swift-language-guide/language-guide/21-protocols
'Mobile > ios' 카테고리의 다른 글
[ios] swift 기본 문법 정리 20: Generics (0) | 2022.12.09 |
---|---|
[ios] swift 기본 문법 정리 19: Extensions (0) | 2022.12.09 |
[ios] swift 기본 문법 정리 17: Type Casting (0) | 2022.12.08 |
[ios] swift 기본 문법 정리 16: Error Handling (0) | 2022.12.08 |
[ios] swift 기본 문법 정리 15: Optional Chaining (0) | 2022.12.07 |
- 인천 구월동 이탈리안 맛집
- await
- react
- react-native
- 인천 구월동 맛집
- redux-thunk
- 파니노구스토
- 이탈리안 레스토랑
- AsyncStorage
- 맛집
- Promise
- redux
- 정보보안기사 #실기 #정리
- Async
- javascript
- Total
- Today
- Yesterday