Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- combine
- 리펙터링
- MVVM
- ribs
- uiscrollview
- RxCocoa
- UITextView
- map
- Clean Code
- swift documentation
- clean architecture
- Xcode
- Observable
- collectionview
- 클린 코드
- swiftUI
- 스위프트
- uitableview
- Protocol
- UICollectionView
- tableView
- 리팩토링
- Refactoring
- 애니메이션
- 리펙토링
- ios
- HIG
- rxswift
- Human interface guide
- SWIFT
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift 공식 문서] 21. Protocols (프로토콜) 본문
Protocol (프로토콜)
- protocol이란 특정 작업이나 기능에 맞게 method, property 및 기타 요구 사항의 청사진을 정의
- protocol은 해당 요구 사항의 실제 구현을 제공하기 위해 class, struct, enum에 의해 'conform'될 수 있는 것
- protocol을 채택하는 것을 swift에서 'conform' 명명
protocol에서 property 정의
- let은 불가, var만 가능
- { get set }이나 { get } 속성 제공
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
- protocol에서 static 정의
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
protocol에서 Method 정의
- instance method
protocol RandomNumberGenerator {
func random() -> Double
}
- type method
protocol SomeProtocol {
static func someTypeMethod()
}
protocol에서 mutating method 정의
- mutating func 키워드 사용
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()
protocol에서 init 정의
- init을 정의한 protocol을 conform하는 곳에서는 required 키워드가 필수
protocol SomeProtocol {
init(someParameter: Int)
}
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
}
- sub class가 상속, conform하고 있는 class와 protocol 각각 모두 시그니쳐도 같은 init() {}를 구현하고 있을 때,
required override 키워드로 선언
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
required override init() {
}
}
Type으로서의 protocol
- Type은 Parent이지만 주입받는 객체는 Child - 업캐스팅
// 최종 캐스팅 되는 유형이 parent이면 업캐스팅, child이면 다운 캐스팅
let p: Parent = Child() // 업캐스팅 ... p는 Parent type
let c: Child = p as? Child // 다운 캐스팅 ... p는 Child type
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())")
}
- 다운 캐스팅해서 사용 가능
var sample = Dice(generator: LinearCongruentialGenerator()) // 업 캐스팅
let sampleDownCasting = sample as? LinearCongruentialGenerator() // 다운 캐스팅
sampleDownCasting.someFunctionLinearCongruentialGenerator()
Delegate
- Delegate는 class나 struct가 일부 책임을 다른 유형의 instance에 넘길 수 있도록 하는 디자인 패턴
protocol DiceGame {
var dice: Dice { get }
func play()
}
protocol DiceGameDelegate: AnyObject {
func gameDidStart(_ game: DiceGame)
func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
func gameDidEnd(_ game: DiceGame)
}
- Strong reference cycle을 피하기 위해서 delegate는 weak로 선언
- weak로 선언하지 않으면 delegate가 참조하는 함수들의 reference count가 상승하여 memory leak 발생을 주의
class SnakesAndLadders: DiceGame {
let finalSquare = 25
let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
var square = 0
var board: [Int]
init() {
board = Array(repeating: 0, count: finalSquare + 1)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
}
weak var delegate: DiceGameDelegate?
func play() {
square = 0
delegate?.gameDidStart(self)
gameLoop: while square != finalSquare {
let diceRoll = dice.roll()
delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
switch square + diceRoll {
case finalSquare:
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
delegate?.gameDidEnd(self)
}
}
Extension으로 protocol conform 추가
- 기존 type의 소스 코드에 액세스할 수 없는 경우라도 기존 type을 확장하여 새 프로토콜을 conform 가능
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
조건적으로 protocol을 comform하는 방법
- where키워드와 특정 타입 정의
- Element가 TextRepresentable을 따르고 Array가 TextRepresentable을 따르고 있는 경우
extension Array: TextRepresentable where Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
extension으로 protocol 채택 선언
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
Class 전용 protocol
- AnyObject 키워드 선언
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
protocol에서 & 연산자
- and조건이며, 아래 코드에선 Location과 Named 프로토콜을 모두 준수하는 파라미터만 인수로 채택 가능
func beginConcert(in location: Location & Named) {
print("Hello, \(location.name)!")
}
protocol에 optional 표시
- @objc 키워드 입력: 해당 property나 method는 conform하지 않아도 되는 것
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
'swift 공식 문서' 카테고리의 다른 글
[iOS - swift 공식 문서] 23. Opaque result Type (불투명 반환 타입 some) (0) | 2021.07.23 |
---|---|
[iOS - swift 공식 문서] 22. Generics (제네릭스) (0) | 2021.07.21 |
[iOS - swift 공식 문서] 20. Extensions (확장) (0) | 2021.07.19 |
[iOS - swift 공식 문서] 19. Nested Type (중첩 타입) (0) | 2021.07.17 |
[iOS - swift 공식 문서] 18. Type Casting (타입 캐스팅, 다운캐스팅, 업캐스팅) (0) | 2021.07.15 |
Comments