Upload
kwang-woo-nam
View
44
Download
0
Embed Size (px)
Citation preview
Swift 3 : Protocols
군산대학교 컴퓨터정보통신공학부 컴퓨터정보공학전공
남 광 우
Swift 3 Tour and Language Guide by Apple
Protocol• 정의
• 특정 태스크나 기능들에 대한 메소드, 속성, 또는 요구사항들의 기본 사항들을 정의
• Java 등의 인터페이스(interface)
• 사용• interface와 동일하게 다중 구현이 가능
• 객체 상속은 1개만
protocol 프로토콜이름 {// protocol definition goes here
}
Protocol• 사용
• protocol의 다중 구현
• class와 potocol의 복합 사용
struct SomeStructure: FirstProtocol, AnotherProtocol {// structure definition goes here
}
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {// class definition goes here
}
Protocol : Property• Property 구현 요구사항 정의
• static 키워드
protocol SomeProtocol {var mustBeSettable: Int { get set }var doesNotNeedToBeSettable: Int { get }
}
protocol AnotherProtocol {static var someTypeProperty: Int { get set }
}
Protocol : Property
• protocol 사용의 예• FullyNamed protocol
• Person struct
protocol FullyNamed {var fullName: String { get }
}
struct Person: FullyNamed {var fullName: String
}
let john = Person(fullName: "John Appleseed")// john.fullName is "John Appleseed"
Protocol : Property
• protocol 사용의 예• Starship class
class Starship: FullyNamed {var prefix: String?var name: Stringinit(name: String, prefix: String? = nil) {
self.name = nameself.prefix = prefix
}var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name}
}var ncc1701 = Starship(name: "Enterprise", prefix: "USS")// ncc1701.fullName is "USS Enterprise"
Protocol : Method
• method protocol
• method protocol의 예
protocol SomeProtocol {static func someTypeMethod()
}
protocol RandomNumberGenerator {func random() -> Double
}
Protocol : Method
• method protocol의 예
class LinearCongruentialGenerator: RandomNumberGenerator {var lastRandom = 42.0let m = 139968.0let a = 3877.0let c = 29573.0func random() -> Double {
lastRandom = ((lastRandom * a +).truncatingRemainder(dividingBy:m))return lastRandom / m
}}let generator = LinearCongruentialGenerator()print("Here's a random number: \(generator.random())")// Prints "Here's a random number: 0.37464991998171“
print("And another one: \(generator.random())")// Prints "And another one: 0.729023776863283"
Protocol : Mutating Method
• mutating method protocol
• 예
protocol Togglable {mutating func toggle()
}
enum OnOffSwitch: Togglable {case off, onmutating func toggle() {
switch self {case .off:
self = .oncase .on:
self = .off}
}}var lightSwitch = OnOffSwitch.offlightSwitch.toggle()// lightSwitch is now equal to .on
Protocol : Initializer
• init protocol
• initializer 프로토콜을 구현 할 경우 required 명시
protocol SomeProtocol {init(someParameter: Int)
}
class SomeClass: SomeProtocol {required init(someParameter: Int) {
// initializer implementation goes here}
}
Protocol : Initializer
• init protocol의 예 • 복합 상속에서의 사용
protocol SomeProtocol {init()
}
class SomeSuperClass {init() {
// initializer implementation goes here}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {required override init() {
// initializer implementation goes here}
}
Type으로서의 protocol
• Type으로 protocol 사용 예 • RandomNumberGenerator
• 사용
class Dice {let sides: Intlet generator: RandomNumberGeneratorinit(sides: Int, generator: RandomNumberGenerator) {
self.sides = sidesself.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 패턴에서의 사용
• Delegation(위임) 패턴이란?• 특정 클래스의 구현 중 일부를 다른 클래스에서 구현
할 수 있도록 하는 패턴
참고 : http://seorenn.blogspot.kr/2015/01/swift‐delegation‐pattern.html
class A
protocol P {pmethod
}
var delegate: P
amethod(){//다른 클래스에
서 구현할 메소드dp.pmethod()
}
class B : P
var da : A
a = A();b = B();a.delegate = b;
pmethod(){
}
da.amethod();
class C : P
var da : A
pmethod(){
}
da.amethod();
a = A();c = C();a.delegate = c;
Delegation 패턴에서의 사용
• DiceGame에서의 Delegation
protocol DiceGame {var dice: Dice { get }func play()
}
protocol DiceGameDelegate {func gameDidStart(_ game: DiceGame)func game(_ game: DiceGame, idStartNewTurnWithDiceRoll diceRoll: Int)func gameDidEnd(_ game: DiceGame)
}
Delegation 패턴에서의 사용
• DiceGame에서의 Delegation
class SnakesAndLadders: DiceGame {let finalSquare = 25let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())var square = 0var board: [Int]init() {
board = Array(repeating: 0, count: finalSquare + 1)board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
}var delegate: DiceGameDelegate?func play() {
square = 0delegate?.gameDidStart(self)gameLoop: while square != finalSquare {
let diceRoll = dice.roll()delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)switch square + diceRoll {case finalSquare:
break gameLoopcase let newSquare where newSquare > finalSquare:
continue gameLoopdefault:
square += diceRollsquare += board[square]
}}delegate?.gameDidEnd(self)
}}
Delegation 패턴에서의 사용
• DiceGameTracker의 구현
class DiceGameTracker: DiceGameDelegate {var numberOfTurns = 0func gameDidStart(_ game: DiceGame) {
numberOfTurns = 0if game is SnakesAndLadders {
print("Started a new game of Snakes and Ladders")}print("The game is using a \(game.dice.sides)-sided dice")
}func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
numberOfTurns += 1print("Rolled a \(diceRoll)")
}func gameDidEnd(_ game: DiceGame) {
print("The game lasted for \(numberOfTurns) turns")}
}
Delegation 패턴에서의 사용
• DiceGame과 DiceGameTracker의 연결
let tracker = DiceGameTracker()let game = SnakesAndLadders()
game.delegate = tracker
game.play()// Started a new game of Snakes and Ladders// The game is using a 6-sided dice// Rolled a 3// Rolled a 5// Rolled a 4// Rolled a 5// The game lasted for 4 turn
Extension과 Protocol
protocol TextRepresentable {var textualDescription: String { get }
}
extension Dice: TextRepresentable {var textualDescription: String {
return "A \(sides)-sided dice"}
}
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())print(d12.textualDescription)// Prints "A 12-sided dice"
class Dice {let sides: Intlet generator: RandomNumberGeneratorinit(sides: Int, generator: RandomNumberGenerator) {
self.sides = sidesself.generator = generator
}func roll() -> Int {
return Int( generator.random() * Double(sides)) + 1}
}
extension SnakesAndLadders: TextRepresentable {var textualDescription: String {
return "A game of Snakes and Ladders with \(finalSquare) squares"}
}
print( game.textualDescription )// Prints "A game of Snakes and Ladders with 25 squares"
Extension과 Protocol
let tracker = DiceGameTracker()let game = SnakesAndLadders()
game.delegate = tracker
game.play()
Protocol Adoption
struct Hamster {var name: Stringvar textualDescription: String {
return "A hamster named \(name)"}
}
extension Hamster: TextRepresentable {}
let simonTheHamster = Hamster(name: "Simon")let somethingTextRepresentable: TextRepresentable = simonTheHamsterprint( somethingTextRepresentable.textualDescription )// Prints "A hamster named Simon"
Protocol Type의 Collection
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
Protocol 상속
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {// protocol definition goes here
}
protocol PrettyTextRepresentable: TextRepresentable {var prettyTextualDescription: String { get }
}
• Protocol의 상속 정의
• protocol 상속의 예
extension SnakesAndLadders: PrettyTextRepresentable {var prettyTextualDescription: String {
var output = textualDescription + ":\n"for index in 1...finalSquare {
switch board[index] {case let ladder where ladder > 0:
output += "▲ "case let snake where snake < 0:
output += "▼ "default:
output += "○ "}
}return output
}}
• 상속된 protocol의 사용
Protocol 상속
print(game.prettyTextualDescription)// A game of Snakes and Ladders with 25 squares:// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼
Class-Only Protocol
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {// class-only protocol definition goes here
}
• class 프로토콜
& protocol composition
protocol Named {var name: String { get }
}protocol Aged {
var age: Int { get }}struct Person: Named, Aged {
var name: Stringvar age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}let birthdayPerson = Person(name: "Malcolm", age: 21)wishHappyBirthday(to: birthdayPerson)// Prints "Happy birthday, Malcolm, you're 21!"
Protocol 체크
• protocol의 타입 체크
• is : 상속 체크
• as? : 특정 프로토콜로 downcast 함특정 프로토콜을 구현하지 않은 경우 nil 반환
• as! : 특정 프로토콜로 downcast 함특정 프로토콜을 구현하지 않은 경우 error
Protocol 체크
protocol HasArea {var area: Double { get }
}
class Circle: HasArea {let pi = 3.1415927var radius: Doublevar area: Double { return pi * radius * radius }init(radius: Double) { self.radius = radius }
}
class Country: HasArea {var area: Doubleinit(area: Double) { self.area = area }
}
Protocol 체크
class Animal {var legs: Intinit(legs: Int) { self.legs = legs }
}
let objects: [AnyObject] = [Circle(radius: 2.0),Country(area: 243_610),Animal(legs: 4)
]
for object in objects {if let objectWithArea = object as? HasArea {
print("Area is \(objectWithArea.area)")} else {
print("Something that doesn't have an area")}
}// Area is 12.5663708// Area is 243610.0// Something that doesn't have an area
optional protocol 구현
@objc protocol CounterDataSource {@objc optional func increment(forCount count: Int) -> Int@objc optional var fixedIncrement: Int { get }
}
class Counter {var count = 0var dataSource: CounterDataSource?func increment() {
if let amount = dataSource?.increment?(forCount: count) {count += amount
} else if let amount = dataSource?.fixedIncrement {count += amount
}}
}
• @objc
optional protocol 구현
• @objc 의 예
class ThreeSource: NSObject, CounterDataSource {let fixedIncrement = 3
}
var counter = Counter()counter.dataSource = ThreeSource()for _ in 1...4 {
counter.increment()print(counter.count)
}// 3// 6// 9// 12
optional protocol 구현
• @objc 의 예
class ThreeSource: NSObject, CounterDataSource {let fixedIncrement = 3
}
@objc class TowardsZeroSource: NSObject, CounterDataSource {func increment(forCount count: Int) -> Int {
if count == 0 {return 0
} else if count < 0 {return 1
} else {return -1
}}
}
counter.count = -4counter.dataSource = TowardsZeroSource()for _ in 1...5 {
counter.increment()print(counter.count)
}