31
Swift 3 : Protocols 군산대학교 컴퓨터정보통신공학부 컴퓨터정보공학전공 남광우 [email protected] Swift 3 Tour and Language Guide by Apple

Swift 3 : Protocol

Embed Size (px)

Citation preview

Swift 3 : Protocols

군산대학교 컴퓨터정보통신공학부 컴퓨터정보공학전공

남 광 우

[email protected]

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)

}