Potato
์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์žก๋‹ˆ๋‹ค?๐Ÿฅ” ^___^ ๐Ÿ˜บ github ๋ฐ”๋กœ๊ฐ€๊ธฐ ๐Ÿ‘‰๐Ÿป

Swift/Swift Documents

[Swift] ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ (22) - Protocols (ํ”„๋กœํ† ์ฝœ)

๊ฐ์ž ๐Ÿฅ” 2022. 3. 21. 02:10
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์ž์ž…๋‹ˆ๋‹ค! (์™œ..์˜ค๋žœ๋งŒ์— ์ธ์‚ฌํ•˜๋Š”๊ฒƒ ๊ฐ™์ง€..)
์ผ์ฃผ์ผ๋งŒ์— ๋Œ์•„์˜จ ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ์ž…๋‹ˆ๋‹ค.. ์ด๋ฒˆ์ฃผ ๋‚ด๋‚ด ํ”„๋กœํ† ์ฝœ ๊ด€๋ จํ•ด์„œ๋งŒ ์ •๋ฆฌํ•œ ๊ฒƒ ๊ฐ™์•„์š”. ๊ทธ๋ฆฌ๊ณ  ์• ํ”Œ์•„์นด๋ฐ๋ฏธ์˜ ์‹œ์ž‘์œผ๋กœ ์‹œ๊ฐ„์ด ๋„ˆ๋ฌด๋„ˆ๋ฌด ๋ถ€์กฑํ•˜๋„ค์š” ใ… ใ…  ๊ทธ๋ž˜๋„ ์ง€์น˜์ง€๋„ ์•Š๊ณ  ํ”„๋กœํ† ์ฝœ ์ •๋ฆฌ๋‚ด์šฉ์„ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค. ๋‚ด์šฉ์ด ๋„ˆ~~~~~๋ฌด ๋งŽ์•„์„œ,, ๋ชจ๋“  ๋‚ด์šฉ์ด ๋‹ค ๋จธ๋ฆฟ์†์— ๋“ค์–ด์˜ค์ง„ ์•Š์€ ๊ฒƒ๊ฐ™์•„์š” ใ…  ๋” ์ฝ์–ด๋ณด๊ณ , ์‹ค๋ฌด์—์„œ ์ ‘ํ•ด๋ณด๋Š” ๋ฐฉ๋ฒ• ๋ฟ์ด๊ฒŸ์ฃ ? ๊ทธ๋Ÿผ ์ฆ๊ฑฐ์šด ๋งˆ์Œ์œผ๋กœ ์‹œ์ž‘ํ•ด๋ด…์‹œ๋‹ค! gogo

Swift Document chap.22 Protocols (ํ”„๋กœํ† ์ฝœ) ๋ฐ”๋กœ๊ฐ€๊ธฐ

 

Protocols — The Swift Programming Language (Swift 5.6)

Protocols A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of tho

docs.swift.org


Protocols (ํ”„๋กœํ† ์ฝœ ; ๊ทœ์•ฝ)

ํ”„๋กœํ† ์ฝœ์€ ํŠน๋ณ„ํ•œ ์ž„๋ฌด ๋˜๋Š” ๊ธฐ๋Šฅ ์กฐ์ž‘์— ์ ํ•ฉํ•œ ๋ฉ”์„œ๋“œ์™€, ํ”„๋กœํผํ‹ฐ, ์š”๊ตฌ์‚ฌํ•ญ์˜ ์ฒญ์‚ฌ์ง„์„ ์ •์˜ํ•œ๋‹ค. ๊ทธ๋Ÿฐ ๋’ค ์ด๋Ÿฐ ์š”๊ตฌ์‚ฌํ•ญ์˜ ์‹ค์ œ ๊ตฌํ˜„์„ ์œ„ํ•ด class, struct, enum์—์„œ protocol์„ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ protocol์ด ์š”๊ตฌํ•˜๋Š” ์‚ฌํ•ญ๋“ค์„ ๋ชจ๋‘ ์ถฉ์กฑํ•˜๋ฉด ํ•ด๋‹น ํƒ€์ž…์€ Protocol์„ ์ค€์ˆ˜ํ•œ๋‹ค๊ณ  ๋งํ•œ๋‹ค.

์ค€์ˆ˜ํ•ด์•ผํ•˜๋Š” ํƒ€์ž…์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ •์˜ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ์š”๊ตฌ์‚ฌํ•ญ์˜ ์ผ๋ถ€๋ฅผ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…์— ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœํ† ์ฝœ์„ ํ™•์žฅํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

Protocol Syntax (ํ”„๋กœํ† ์ฝœ ๊ตฌ๋ฌธ)

ํ”„๋กœํ† ์ฝœ์€ ํด๋ž˜์Šค, ๊ตฌ์กฐ์ฒด ๋ฐ ์—ด๊ฑฐํ˜•๊ณผ ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ ์ •์˜ํ•œ๋‹ค.

protocol SomeProtocol {
  // ํ”„๋กœํ† ์ฝœ ์ •์˜๋Š” ์—ฌ๊ธฐ์— ๋‘ 
}

์‚ฌ์šฉ์ž ์ •์˜ ํƒ€์ž…์€, ์ž์‹ ์˜ ์ •์˜ ๋ถ€๋ถ„์—์„œ ํƒ€์ž… ์ด๋ฆ„ ๋’ค์— ํ”„๋กœํ† ์ฝœ ์ด๋ฆ„์„ ์ฝœ๋ก ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋‘ ์œผ๋กœ์จ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๊ณ  ์•Œ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ”„๋กœํ† ์ฝœ์„ ์‰ผํ‘œ,๋กœ ๋‚˜๋ˆ„์–ด ๋‚˜์—ดํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

struct SomeStructure: FirstProtocol, AnotherProtocol {
  // ๊ตฌ์กฐ์ฒด ์ •์˜๋Š” ์—ฌ๊ธฐ์— ๋‘ 
}

ํด๋ž˜์Šค์— ์ƒ์œ„ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด, ์ƒ์œ„ ํด๋ž˜์Šค ์ด๋ฆ„ ๋จผ์ € ์ž‘์„ฑํ•œ ํ›„, ๊ทธ ๋’ค์— ์‰ผํ‘œ,๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค.

class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
  // ํด๋ž˜์Šค ์ •์˜๋Š” ์—ฌ๊ธฐ์— ๋‘ 
}

 

1. ํ”„๋กœํผํ‹ฐ ํ•„์ˆ˜ ์กฐ๊ฑด (Property Requirements)

  • ํ”„๋กœํ† ์ฝœ์€ ํŠน์ • ์ด๋ฆ„๊ณผ ํƒ€์ž…์„ ๊ฐ–๋Š” ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ, ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์š”๊ตฌํ•˜๋Š” ํƒ€์ž…์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Œ.
  • ํ”„๋กœํ† ์ฝœ์€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ €์žฅ ํ”„๋กœํผํ‹ฐ์ธ์ง€ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ์ธ์ง€ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ํ•„์š”ํ•œ ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฆ„๊ณผ ํƒ€์ž…๋งŒ ์ง€์ •ํ•จ.
  • ํ”„๋กœํ† ์ฝœ์€ ๊ฐ๊ฐ์˜ ํ”„๋กœํ„ฐํ”ผ๊ฐ€ gettable, settable ํ•œ์ง€๋„ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•จ.
  • ํ”„๋กœํ† ์ฝœ์—์„œ gettable, settable ๋‘˜ ๋‹ค ์š”๊ตฌํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋Š” ์ƒ์ˆ˜ ์ €์žฅ ํ”„๋กœํผํ‹ฐ ํ˜น์€ ์ฝ๊ธฐ ์ „์šฉ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ๋กœ๋Š” ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์—†์Œ.
  • ํ”„๋กœํ† ์ฝœ์ด gettable ํ”„๋กœํผํ‹ฐ๋งŒ ์š”๊ตฌํ•  ๊ฒฝ์šฐ, ๋ชจ๋“  ์ข…๋ฅ˜์˜ ํ”„๋กœํผํ‹ฐ๋กœ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ณ , ์ด๋Ÿฐ ํ”„๋กœํผํ‹ฐ๋Š” settable ์—์„œ๋„ ์œ ํšจํ•จ.

ํ”„๋กœํผํ‹ฐ ์š”๊ตฌ์‚ฌํ•ญ์€ ํ•ญ์ƒ var ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ ์„ ์–ธ๋œ๋‹ค. gettable , settable ํ”„๋กœํผํ‹ฐ๋Š” ํƒ€์ž… ์„ ์–ธ ๋’ค์— { get set } ์œผ๋กœ ์ž‘์„ฑํ•ด์„œ ๋‚˜ํƒ€๋‚ด๋ฉฐ, gettable ํ”„๋กœํผํ‹ฐ๋Š” { get } ์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

protocol SomeProtocol {
  var mustBeSettable: Int { get set }
  var doesNotNeedToBeSettable: Int { get }
}

ํ”„๋กœํ† ์ฝœ์—์„œ ํƒ€์ž…ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•  ๋• ํ•ญ์ƒ static ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์ด ๊ทœ์น™์€ Class ์— ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ๊ฒฝ์šฐ์— class, static ํ‚ค์›Œ๋“œ๋ฅผ ์“ฐ๋Š” ๊ฒฝ์šฐ์—๋„ ์ ์šฉ๋œ๋‹ค.

protocol AnotherProtocol {
  static var someTypeProperty: Int { get set }
}

 

โ–ถ๏ธ ์ด์ œ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

protocol FullyNamed {
  var fullName: String { get }
}

FullyNamed ํ”„๋กœํ† ์ฝœ์€ ํ’€๋„ค์ž„์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์ค€์ˆ˜ํ•ด์•ผํ•˜๋Š” ํƒ€์ž…์„ ์š”๊ตฌํ•œ๋‹ค. ํ”„๋กœํ† ์ฝœ์€ ๋‹ค๋ฅธ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…์˜ ํŠน์„ฑ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ๊ฒƒ์„ ์ง€์ •ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. ํ”„๋กœํ† ์ฝœ์€ ํƒ€์ž…์—๊ฒŒ fullName์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ๋งŒ ์ •ํ•ด์ค€๋‹ค. ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ๋ชจ๋“  FullyNamed ํƒ€์ž…์—๋Š” String ํƒ€์ž…์˜ fullName์ด๋ผ๋Š” gettable ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•ด์•ผํ•œ๋‹ค.

๋‹ค์Œ์€ FullyNamed ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์ค€์ˆ˜ํ•˜๋Š” struct์— ๋Œ€ํ•œ ์—์‹œ์ด๋‹ค.

struct Person: FullyNamed {
  var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName ์€ "John Appleseed" ์ž„

์œ„ ์ฝ”๋“œ๋Š” ํŠน์ • ์ด๋ฆ„์„ ๊ฐ€์ง„ ์‚ฌ๋žŒ์„ ๋‚˜ํƒ€๋‚ด๋Š” Person์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ์ •์˜ ์ฒซ ์ค„์—์„œ FullyNamed ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๊ณ  ์ž‘์„ฑํ–ˆ๋‹ค.

๊ฐ๊ฐ์˜ Person ์ธ์Šคํ„ด์Šค๋Š” String ํƒ€์ž…์˜ FullName์ด๋ผ๋Š” ๋‹จ์ผ ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๋Š”๋‹ค. ์ด๋Š” FullyNamed ํ”„๋กœํ† ์ฝœ์˜ ๋‹จ์ผ ํ•„์ˆ˜ ์กฐ๊ฑด๊ณผ ์ผ์น˜ํ•˜๋ฉฐ Person์ด ํ”„๋กœํ† ์ฝœ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ค€์ˆ˜ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ๋งŒ์•ฝ ํ”„๋กœํ† ์ฝœ์˜ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

FullyNamed ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์ค€์ˆ˜ํ•˜๋Š” ๋” ๋ณต์žกํ•œ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

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 ์€ "USS Enterprise" ์ž„

์ด ํด๋ž˜์Šค๋Š” fullName ํ”„๋กœํผํ‹ฐ ํ•„์ˆ˜ ์กฐ๊ฑด์„ starship์˜ ์ฝ๊ธฐ ์ „์šฉ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค. ๊ฐ๊ฐ์˜ Starship ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋Š” ์˜๋ฌด์ ์ธ name๊ณผ ์˜ต์…˜์ธ prefix๋ฅผ ์ €์žฅํ•œ๋‹ค. prefix ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด, fullName ํ”„๋กœํผํ‹ฐ๊ฐ€, name์•ž์— ์ด๋ฅผ ๋ถ™์—ฌ ์šฐ์ฃผ์„  ์ „์ฒด ์ด๋ฆ„์„ ์ƒ์„ฑํ•œ๋‹ค.

 

2. ๋ฉ”์„œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด (Method)

ํ”„๋กœํ† ์ฝœ์€ ์ž์‹ ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์—๊ฒŒ ํŠน์ • ์ธ์Šคํ„ด์Šค๋‚˜ ํƒ€์ž… ๋ฉ”์„œ๋“œ๋ฅผ ์š”๊ตฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜์ ์ธ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ, ํƒ€์ž… ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ”„๋กœํ† ์ฝœ ๋‚ด๋ถ€์— ์ž‘์„ฑ๋˜์ง€๋งŒ, ์ค‘๊ด„ํ˜ธ๋‚˜ ๋ฉ”์„œ๋“œ ๋ณธ๋ฌธ์€ ์—†๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ฉ”์„œ๋“œ์™€ ๋™์ผํ•œ ๊ทœ์น™์— ๋”ฐ๋ผ ๊ฐ€๋ณ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํ—ˆ์šฉ๋˜์ง€๋งŒ, ํ”„๋กœํ† ์ฝœ ์ •์˜ ๋‚ด์—์„œ๋Š” ๋ฉ”์„œ๋“œ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๊ธฐ๋ณธ ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜๋Š” ์—†๋‹ค.

ํƒ€์ž… ํ”„๋กœํผํ‹ฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ํ”„๋กœํ† ์ฝœ์—์„œ ํƒ€์ž… ๋ฉ”์„œ๋“œ ์กฐ๊ฑด์„ ์ •์˜ํ•  ๋•Œ๋Š” ํ•ญ์ƒ static ํ‚ค์›Œ๋“œ ์ ‘๋‘์‚ฌ๋ฅผ ๋ถ™์ธ๋‹ค. ํƒ€์ž… ๋ฉ”์„œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„ํ•  ๋•Œ class ๋‚˜ static ํ‚ค์›Œ๋“œ ์ ‘๋‘์‚ฌ๋ฅผ ๋ถ™๋”๋ผ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค.

protocol SomeProtocol {
  static func someTypeMethod()
}

๋‹ค์Œ ์˜ˆ์ œ๋Š” ๋‹จ์ผ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๊ฐ€์ง„ ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

protocol RandomNumberGenerator {
  func random() -> Double
}

RandomNumberGenerator ์ด๋ผ๋Š” ์ด ํ”„๋กœํ† ์ฝœ์€ ์–ด๋–ค ์ค€์ˆ˜ ํƒ€์ž…์ด๋“  random์ด๋ผ๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ธฐ๋ฅผ ์š”๊ตฌํ•˜๋Š”๋ฐ, ์ด๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค double ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ํ”„๋กœํ† ์ฝœ์—์„œ ์ง€์ •ํ•˜์ง€ ์•Š๊ธด ํ•˜์ง€๋งŒ, ์ด ๊ฐ’์€ 0.0์—์„œ 1.0๊นŒ์ง€์˜ ๊ฐ’์ด๋ผ ๊ฐ€์ •ํ•œ๋‹ค. (1.0 ๋ฏธํฌํ•จ)

RandomNumberGenerator ํ”„๋กœํ† ์ฝœ์€ ๊ฐ๊ฐ์˜ ๋‚œ์ˆ˜ ๋ฐœ์ƒ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„  ์–ด๋–ค ๊ฐ€์ •๋„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ƒ์„ฑ์ž๊ฐ€ ์ƒˆ๋กœ์šด ๋‚œ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ‘œ์ค€ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

๋‹ค์Œ์œผ๋กœ๋Š” RandomNumberGenerator ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์ค€์ˆ˜ํ•˜๋Š” class๋ฅผ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ด๋‹ค. ์ด ํด๋ž˜์Šค๋Š” linear congruential generator๋กœ ์•Œ๋ ค์ง„ pseudorandom number generator ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•œ๋‹ค.

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())")
// "Here's a random number: 0.3746499199817101" ๋ฅผ ์ธ์‡„ํ•จ
print("And another one: \\(generator.random())")
// "And another one: 0.729023776863283" ๋ฅผ ์ธ์‡„ํ•จ

 

3. ๋ณ€๊ฒฝ ๋ฉ”์„œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด (Mutating Methods)

๋ฉ”์„œ๋“œ๊ฐ€ ์ž์‹ ์ด ์†ํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ˆ˜์ •(๋ณ€๊ฒฝ)ํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ๊ฐ’ ํƒ€์ž…์˜ (๊ตฌ์กฐ์ฒด์™€ ์—ด๊ฑฐํ˜•)์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์ด๋ฉด, ๋ฉ”์„œ๋“œ์˜ func ํ‚ค์›Œ๋“œ ์•ž์— mutating ํ‚ค์›Œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๋ฉ”์„œ๋“œ๊ฐ€ ์ž์‹ ์ด ์†ํ•œ ์ธ์Šคํ„ด์Šค ๋ฐ ๊ทธ ์ธ์Šคํ„ด์Šค์— ์žˆ๋Š” ์–ด๋–ค ์†์„ฑ์˜ ์ˆ˜์ •์ด๋“  ํ—ˆ์šฉํ•œ๋‹ค๊ณ  ์ง€์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ์–ด๋–ค ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋“  ๋ณ€๊ฒฝํ•  ์˜๋„๋กœ ํ”„๋กœํ† ์ฝœ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ์ •์˜ํ•˜๋Š” ๊ฑฐ๋ผ๋ฉด, ํ”„๋กœํ† ์ฝœ ์ •์˜ ๋ถ€๋ถ„์—์„œ mutating ํ‚ค์›Œ๋“œ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค. ์ด๋Š” ๊ตฌ์กฐ์ฒด ๋ฐ ์—ด๊ฑฐํ˜•์ด ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด์„œ ๊ทธ ๋ฉ”์„œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

โ–ถ๏ธ Note

ํ”„๋กœํ† ์ฝœ์ด ์š”๊ตฌํ•˜๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์— mutating ์„ ํ‘œ์‹œํ•˜๋”๋ผ๋„ ํด๋ž˜์Šค๋Š” ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ mutatingํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. mutating ์€ ๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐํ˜•์˜ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

 

๋‹ค์Œ์€ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์š”๊ตฌํ•˜๋Š” Togglable ํ”„๋กœํ† ์ฝœ ์ด๋‹ค. ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ, toggle() ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•ด๋‹น ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ˆ˜์ •ํ•ด์„œ ํ•ด๋‹น ํƒ€์ž…์˜ ์ƒํƒœ๋ฅผ ์ „ํ™˜ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์ด๋‹ค.

toggle() ๋ฉ”์„œ๋“œ๋Š” Togglable ํ”„๋กœํ† ์ฝœ ์ •์˜์˜ ์ผ๋ถ€๋กœ mutating ํ‚ค์›Œ๋“œ๋กœ ํ‘œ์‹œ๋˜์–ด ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค€๋‹ค.

protocol Togglable {
  mutating func toggle()
}

๊ตฌ์กฐ์ฒด๋‚˜ ์—ด๊ฑฐํ˜•์ด Togglable ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•˜๋ฉด, mutating ์œผ๋กœ๋„ ํ‘œ์‹œํ•œ toggle()๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ ๊ทธ ๊ตฌ์กฐ์ฒด๋‚˜ ์—ด๊ฑฐํ˜•์ด ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜ ์˜ˆ์ œ๋Š” OnOffSwitch ๋ผ๋Š” ์—ด๊ฑฐํ˜•์„ ์ •์˜ํ•œ๋‹ค. ์ด ์—ด๊ฑฐํ˜•์€ on ๊ณผ off ์—ด๊ฑฐํ˜• case ๋กœ ํ‘œ์‹œํ•œ ๋‘ ์ƒํƒœ ์‚ฌ์ด๋ฅผ ์ „ํ™˜ํ•œ๋‹ค. Togglable ํ”„๋กœํ† ์ฝœ์˜ ํ•„์ˆ˜ ์กฐ๊ฑด๊ณผ ์ผ์น˜ํ•˜๋„๋ก, ์—ด๊ฑฐํ˜•์˜ toggle ๊ตฌํ˜„์— mutating ์„ ํ‘œ์‹œํ–ˆ๋‹ค.

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 ๋Š” ์ด์ œ .on ๊ณผ ๊ฐ™์Œ

 

4. ์ƒ์„ฑ์ž ํ•„์ˆ˜ ์กฐ๊ฑด (Initializer requirements)

ํ”„๋กœํ† ์ฝœ์€ ์ค€์ˆ˜ ํƒ€์ž…์—๊ฒŒ ํŠน์ • ์ƒ์„ฑ์ž ๊ตฌํ˜„์„ ์š”๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์ƒ์„ฑ์ž๋“ค์€ ๋ณดํ†ต์˜ ์ƒ์„ฑ์ž์™€ ์ •ํ™•ํžˆ ๋˜‘๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํ”„๋กœํ† ์ฝœ์˜ ์ •์˜ ๋ถ€๋ถ„์— ์ž‘์„ฑํ•˜์ง€๋งŒ, ์ค‘๊ด„ํ˜ธ๋‚˜ ๋ฉ”์„œ๋“œ ๋ณธ๋ฌธ์ด ์—†๋‹ค.

protocol SomeProtocol {
  init(someParameter: Int)
}

ํ”„๋กœํ† ์ฝœ ์ƒ์„ฑ์ž ํ•„์ˆ˜ ์กฐ๊ฑด์˜ ํด๋ž˜์Šค ๊ตฌํ˜„ (required ํ‚ค์›Œ๋“œ)

ํ”„๋กœํ† ์ฝœ ์ƒ์„ฑ์ž ํ•„์ˆ˜ ์กฐ๊ฑด์€ ์ค€์ˆ˜ ํด๋ž˜์Šค์—์„œ designated ์ƒ์„ฑ์ž๋‚˜ convenience ์ƒ์„ฑ์ž ์–ด๋Š ๊ฒƒ์œผ๋กœ๋“  ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ **required ํ‚ค์›Œ๋“œ**๋ฅผ ํ‘œ์‹œํ•ด์•ผํ•œ๋‹ค.

class SomeClass: SomeProtocol {
  **required** init(someParameter: Int) {
    // ์ดˆ๊ธฐ์ž ๊ตฌํ˜„์€ ์—ฌ๊ธฐ์— ๋‘ 
  }
}

required ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด class์˜ ๋ชจ๋“  ์„œ๋ธŒ ํด๋ž˜์Šค๋„ ํ•ด๋‹น ์ƒ์„ฑ์ž๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜น์€ ์ƒ์†๋œ ๊ตฌํ˜„์„ ํ†ตํ•ด ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ, ๋ถ€๋ชจ ํด๋ž˜์Šค๊ฐ€ ์ฑ„ํƒ์ค‘์ธ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. reqiured ์ƒ์„ฑ์ž์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์ •๋ณด๋Š” chap.14์—์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

โ–ถ๏ธ Note

final ํด๋ž˜์Šค๋Š” ์„œ๋ธŒํด๋ž˜์‹ฑ ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— final ํด๋ž˜์Šค๋Š” ํ”„๋กœํ† ์ฝœ์ด ์š”๊ตฌํ•˜๋Š” ์ƒ์„ฑ์ž์— required๋ฅผ ํ•„์š”ํ•  ํ‘œ์‹œ๊ฐ€ ์—†๋‹ค.

 

ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์ƒ์œ„ ํด๋ž˜์Šค์˜ designated ์ƒ์„ฑ์ž๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•˜๋ฉด์„œ ํ”„๋กœํ† ์ฝœ์˜ ์ผ์น˜ํ•˜๋Š” ์ƒ์„ฑ์ž ํ•„์ˆ˜ ์กฐ๊ฑด๋„ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด, ์ƒ์„ฑ์ž ๊ตฌํ˜„์— required ์™€ override ํ‚ค์›Œ๋“œ๋ฅผ ๋ชจ๋‘ ํ‘œ์‹œํ•œ๋‹ค.

protocol SomeProtocol {
  init()
}

class SomeSuperClass {
  init() {
    // ์ดˆ๊ธฐ์ž ๊ตฌํ˜„์€ ์—ฌ๊ธฐ์— ๋‘ 
  }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
  // "required" ๋Š” SomeProtocol ์ค€์ˆ˜์—์„œ; "override" ๋Š” SomeSuperClass ์—์„œ ์˜จ ๊ฒƒ์ž„
  **required override** init() {
    // ์ดˆ๊ธฐ์ž ๊ตฌํ˜„์€ ์—ฌ๊ธฐ์— ๋‘ 
  }
}

 

5. Failable Initializer Requirement (์‹คํŒจ ๊ฐ€๋Šฅํ•œ ์ƒ์„ฑ์ž ํ•„์ˆ˜ ์กฐ๊ฑด)

chap.14์—์„œ Failable Initializer์— ์ •์˜๋œ ๊ฒƒ์ฒ˜๋Ÿผ, ํ”„๋กœํ† ์ฝœ์€ ์‹คํŒจ ๊ฐ€๋Šฅํ•œ ์ƒ์„ฑ์ž ์š”๊ตฌ์‚ฌํ•ญ์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœํ† ์ฝœ์˜ ์‹คํŒจ ๊ฐ€๋Šฅํ•œ ์ƒ์„ฑ์ž ์š”๊ตฌ์‚ฌํ•ญ์€ ์ž์‹ ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์ด ์‹คํŒจ ๊ฐ€๋Šฅ, ์‹คํŒจ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์„ ๋•Œ ๋งŒ์กฑ๋œ๋‹ค. ์‹คํŒจํ•  ์ˆ˜ ์—†๋Š” ์ƒ์„ฑ์ž๋ฅผ ์š”๊ตฌํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ๊ฒฝ์šฐ, ์‹คํŒจํ•  ์ˆ˜ ์—†๋Š” ์ƒ์„ฑ์ž ๋˜๋Š” ์•”์‹œ์ ์œผ๋กœ ๋ž˜ํ•‘๋˜์ง€ ์•Š๋Š” ์‹คํŒจ ๊ฐ€๋Šฅํ•œ ์ƒ์„ฑ์ž๋กœ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.


 

Protocols as Types (ํƒ€์ž…์œผ๋กœ์จ์˜ ํ”„๋กœํ† ์ฝœ)

ํ”„๋กœํ† ์ฝœ์€ ์ž์ฒด์ ์œผ๋กœ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”๋”ฉ์„ ํ•  ๋•Œ ํ”„๋กœํ† ์ฝœ์€ ํ•˜๋‚˜์˜ ํƒ€์ž…์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ”„๋กœํ† ์ฝœ์„ ํƒ€์ž…์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ **existential type** ์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๋ฐ, ์ด๋Š” ‘T๊ฐ€ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋„๋ก ํƒ€์ž… T ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค’ ๋ผ๋Š” ๋ฌธ๊ตฌ์—์„œ ์œ ๋ž˜๋˜์—ˆ๋‹ค. (?)

๋‹ค์Œ์„ ํฌํ•จํ•˜์—ฌ ๋‹ค๋ฅธ ํƒ€์ž…์ด ํ—ˆ์šฉ๋˜๋Š” ์—ฌ๋Ÿฌ ์œ„์น˜์—์„œ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํ•จ์ˆ˜, ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž… ๋˜๋Š” ๋ฐ˜ํ™˜ ํƒ€์ž…
  • ์ƒ์ˆ˜, ๋ณ€์ˆ˜, ํ”„๋กœํผํ‹ฐ์˜ ํƒ€์ž…
  • ๋ฐฐ์—ด, ๋”•์…”๋„ˆ๋ฆฌ ๋“ฑ์˜ ํ•ญ๋ชฉ ํƒ€์ž…

โ–ถ๏ธ Note

ํ”„๋กœํ† ์ฝœ์ด ํƒ€์ž…์ด๋ฏ€๋กœ (์•ž์—์„œ ๋ดค๋˜ FullyNamed, RandomNumberGenerator ์ฒ˜๋Ÿผ) , Swift์˜ ๋‹ค๋ฅธ ํƒ€์ž…๋“ค (Int, String,,,,) ์ฒ˜๋Ÿผ ์ด๋ฆ„์ด ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•œ๋‹ค.

 

ํ”„๋กœํ† ์ฝœ์„ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž.

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
  }
}

โ–ถ๏ธ ์ฝ”๋“œ ์„ค๋ช…

  • ์ด ์˜ˆ์ œ๋Š” ๋ณด๋“œ๊ฒŒ์ž„์—์„œ ์‚ฌ์šฉํ•  n ๋ฉด์ฒด ์ฃผ์‚ฌ์œ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” Dice๋ผ๋Š” ์ƒˆ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•œ๋‹ค
  • Dice ์ธ์Šคํ„ด์Šค์—๋Š”, sides ๋ผ๋Š” ์ •์ˆ˜ ์†์„ฑ, ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆผ ๊ฐ’ ์ƒ์„ฑ์„ ์œ„ํ•œ ๋‚œ์ˆ˜ ์ƒ์„ฑ generator ์†์„ฑ์ด ์žˆ๋‹ค.
  • **generator** ์†์„ฑํƒ€์ž… ์„ค๋ช…
    • generator ์†์„ฑ ํƒ€์ž…์€ RandomNumberGenerator ์ด๋‹ค. ๋”ฐ๋ผ์„œ RandomNumberGenerator ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ๋ชจ๋“  ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ธ์Šคํ„ด์Šค๊ฐ€ RandomNumberGenerator ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒœํ•œ๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๊ณ  ์ด ์†์„ฑ์— ํ•ด๋‹น๋  ์ธ์Šคํ„ด์Šค ์š”๊ตฌ์‚ฌํ•ญ์€ ์—†๋‹ค.
    • generator์˜ ํƒ€์ž…์ด RandomNumberGenerator ์ด๋ฏ€๋กœ, Dice ํด๋ž˜์Šค ๋‚ด๋ถ€ ์ฝ”๋“œ๋Š” ์ด ํ”„๋กœํ† ์ฝœ์ด ์ค€์ˆ˜ํ•˜๋Š” ๋ชจ๋“  ์ธ์Šคํ„ด์Šค์— ์ ์šฉ๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ๋งŒ generator์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, generator์˜ ๊ธฐ๋ณธ ํƒ€์ž…์— ์ •์˜๋œ ๋ฉ”์„œ๋“œ๋‚˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
    • ํ•˜์ง€๋งŒ ๋‹ค์šด์บ์ŠคํŒ…์—์„œ ์„ค๋ช…ํ•œ ์Šˆํผํด๋ž˜์Šค๋ฅผ ์„œ๋ธŒํด๋ž˜์Šค๋กœ ๋‹ค์šดํด๋ž˜์‹ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํ”„๋กœํ† ์ฝœ ํƒ€์ž…์„ ๊ธฐ๋ณธํƒ€์ž…์œผ๋กœ ๋‹ค์šด์บ์ŠคํŠธํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์žˆ๋‹ค.
  • **init** ์ƒ์„ฑ์ž
    • Dice์˜ ์ดˆ๊ธฐ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ์ƒ์„ฑ์ž
    • RandomNumberGenerator ํƒ€์ž…์˜ generator ๋ผ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌ.
    • ์ƒˆ๋กœ์šด Dice ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ generator ๋งค๊ฐœ๋ณ€์ˆ˜์—๋Š” RandomNumberGenerator๋ฅผ ์ฑ„ํƒํ•œ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ.
  • **roll()** ๋ฉ”์„œ๋“œ
    • Dice๋Š” 1๊ณผ sided ์‚ฌ์ด์˜ ์ •์ˆ˜๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ
    • ์ด ๋ฉ”์„œ๋“œ๋Š” generator์˜ random() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ 0.0~1.0 ์‚ฌ์ด์˜ ์ƒˆ๋กœ์šด ๋‚œ์ˆ˜๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ , ์ด ๋‚œ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฒ”์œ„ ๋‚ด์˜ ๊ฐ’์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.
    • generator๋Š” RandomNumberGenerator๋ฅผ ์ฑ„ํƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— random() ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•จ!!

์œ„์˜ Dice ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ LinearCongruentialGenerator ์ธ์Šคํ„ด์Šค๋ฅผ generator๋กœ ์‚ฌ์šฉํ•ด์„œ 6๋ฉด ์ฃผ์‚ฌ์œ„๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

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

 


 

Delegation (์œ„์ž„)

Delegation์€ ํด๋ž˜์Šค๋‚˜ ๊ตฌ์กฐ์ฒด๊ฐ€ ์ผ๋ถ€ ์ฑ…์ž„์„ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค์— ๋„˜๊ธธ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค. DelegationํŒจํ„ด์€ ์œ„์ž„๋œ ์ฑ…์ž„์„ ์บก์Šํ™”ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•˜์—ฌ ๊ตฌํ˜„๋œ๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์ด ์œ„์ž„๋œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋„๋ก ๋ณด์žฅ๋œ๋‹ค. Delegation์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์ž‘์—…์— ์‘๋‹ตํ•˜๊ฑฐ๋‚˜, ํ•ด๋‹น ์†Œ์Šค์˜ ๊ธฐ๋ณธ ํƒ€์ž…์„ ์•Œ ํ•„์š” ์—†์ด ์™ธ๋ถ€ ์†Œ์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜ ์˜ˆ์‹œ๋Š” ์ฃผ์‚ฌ์œ„ ๊ธฐ๋ฐ˜ ๋ณด๋“œ๊ฒŒ์ž„์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ 2๊ฐœ์˜ ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•œ ์ฝ”๋“œ์ด๋‹ค.

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)
}

DiceGame ํ”„๋กœํ† ์ฝœ์€ ์ฃผ์‚ฌ์œ„์™€ ์—ฎ์ธ ์–ด๋–ค ๊ฒŒ์ž„์ด๋“  ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœํ† ์ฝœ์ด๋‹ค.

DiceGameDelegateํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด DiceGame์˜ ์ง„ํ–‰์ƒํ™ฉ์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ delegate๋Š” weak์ฐธ์กฐ๋กœ ์„ ์–ธ๋œ๋‹ค. weak ์ฐธ์กฐ์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์—ฌ๊ธฐ์„œ ์‚ดํŽด๋ณด์ž.

์ž ์‹œ ๋’ค์— ๋‚˜์˜ค๋Š” class-only ํ”„๋กœํ† ์ฝœ ์„น์…˜์—์„œ ๋‚˜์˜ฌ ๋‚ด์šฉ์„ ๋ฏธ๋ฆฌ ๋ง์”€๋“œ๋ฆฌ๋ฉด, class ์ „์šฉ ํ”„๋กœํ† ์ฝœ์€ AnyObject๋ฅผ ์ƒ์†ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ‘œ์‹œํ•˜๋ฉด ๋œ๋‹ค. ํ”„๋กœํ† ์ฝœ์„ ํด๋ž˜์Šค ์ „์šฉ์œผ๋กœ ํ‘œ์‹œํ•˜๋ฉด ์ด๋ฒˆ ์ฑ•ํ„ฐ์˜ ๋’ท ๋ถ€๋ถ„์— ๋‚˜์˜ค๋Š” SnakesAndLadders ํด๋ž˜์Šค์˜ delegate์ฒ˜๋Ÿผ weak์ฐธ์กฐ๋กœ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ์€ ์›๋ž˜ chap.5 Control Flow ์—์„œ ์†Œ๊ฐœ๋œ snake and ladders ๊ฒŒ์ž„ ๋ฒ„์ „์ด๋‹ค. ์ด ๋ฒ„์ „์€ DiceGame ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  DiceGameDeleagate์—๊ฒŒ ์ง„ํ–‰์ƒํ™ฉ์„ ์•Œ๋ฆฌ๊ธฐ ์œ„ํ•ด dice-roll์— Dice ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค.

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)
  }
}

์ด ๋ฒ„์ „์˜ ๊ฒŒ์ž„์€ DiceGame ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ SnakesAndLadders ํด๋ž˜์Šค๋กœ ๋ž˜ํ•‘๋œ๋‹ค.

์ด๋Š” ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜๋ฅผ ์œ„ํ•ด์„œ gettable dice ํ”„๋กœํผํ‹ฐ์™€ play() ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. (dice ํ”„๋กœํผํ‹ฐ๋Š” ์ƒ์„ฑ ํ›„ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— let์œผ๋กœ ์„ ์–ธ๋˜๋ฉฐ ํ”„๋กœํ† ์ฝœ์€ gettable๋งŒ ์š”๊ตฌํ•˜๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.)

snakes and Ladders ๊ฒŒ์ž„์€ class ์˜ init() ์ƒ์„ฑ์ž์—์„œ ์ด๋ฃจ์–ด์ง„๋‹ค. ๋ชจ๋“  ๊ฒŒ์ž„ ๋…ผ๋ฆฌ๋Š” ํ”„๋กœํ† ์ฝœ์˜ ํ•„์ˆ˜ ์š”์†Œ์ธ dice ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฃผ์‚ฌ์œ„ ์—ญํ• ์„ ์ œ๊ณตํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์˜ play() ๋ฉ”์„œ๋“œ๋กœ ์ง„ํ–‰๋œ๋‹ค.

delegate ํ”„๋กœํผํ‹ฐ๋Š” ์˜ต์…”๋„ DiceGameDelegate ํƒ€์ž…์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ๋‹ค. ์˜ต์…”๋„์ธ ์ด์œ ๋Š” ๊ฒŒ์ž„์„ ํ”Œ๋ ˆ์ดํ•˜๊ธฐ ์œ„ํ•ด delegate๋Š” ํ•„์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์˜ต์…”๋„ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— delegate ํ”„๋กœํผํ‹ฐ์˜ ์ดˆ๊ธฐ๊ฐ’์€ nil ์ด๋‹ค. ๊ทธ๋Ÿฐ ๋’ค ๊ฒŒ์ž„์„ ์ƒ์„ฑํ•œ ๊ณณ์—์„œ ์ ์ ˆํ•œ delegate๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. DiceGameDelegate ํ”„๋กœํ† ์ฝœ์€ ํด๋ž˜์Šค ์ „์šฉ์ด๋ฏ€๋กœ ์ฐธ์กฐ ์ฃผ๊ธฐ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด weak ์œผ๋กœ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

DiceGameDelegatge๋Š” ๊ฒŒ์ž„ ์ง„ํ–‰์ƒํ™ฉ์„ ์ถ”์ ํ•˜๋Š” ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋Š” ์œ„์˜ play() ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ๊ฒŒ์ž„ ๋…ผ๋ฆฌ์— ํ†ตํ•ฉ๋˜์–ด ์ƒˆ๋กœ์šด ๊ฒŒ์ž„์ด ์‹œ์ž‘๋˜๊ฑฐ๋‚˜ ์ƒˆ ์ฐจ๋ก€๊ฐ€ ์˜ค๊ฑฐ๋‚˜ ๊ฒŒ์ž„์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ํ˜ธ์ถœ๋œ๋‹ค.

delegateํ”„๋กœํผํ‹ฐ๋Š” ์˜ต์…”๋„ DiceGameDelegate์ด๋ฏ€๋กœ, play() ๋ฉ”์„œ๋“œ๋Š” delegate ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์˜ต์…”๋„ ์ฒด์ด๋‹์„ ์‚ฌ์šฉํ•œ๋‹ค. delegate ํ”„๋กœํผํ‹ฐ๊ฐ€ nil ์ด๋ผ๋ฉด ์ด๋Ÿฌํ•œ ํ˜ธ์ถœ์€ ์ •์ƒ์ ์œผ๋กœ ์‹คํŒจํ•˜๊ฒŒ ๋˜๊ณ , nil ์ด ์•„๋‹ˆ๋ผ๋ฉด delegate ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  SnakesAndLadders ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋œ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ๋Š” DiceGameDelegate ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ DiceGameTracker๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•œ ์ฝ”๋“œ์ด๋‹ค.

class DiceGameTracker: DiceGameDelegate {
  var numberOfTurns = 0
  func gameDidStart(_ game: DiceGame) {
    numberOfTurns = 0
    if 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 += 1
    print("Rolled a \\(diceRoll)")
  }
  func gameDidEnd(_ game: DiceGame) {
    print("The game lasted for \\(numberOfTurns) turns")
  }
}

DiceGagmeTracker๋Š” DiceGameDelegate์— ํ•„์š”ํ•œ ์„ธ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•ด๋’€๋‹ค. ์ด๋Ÿฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฒŒ์ž„์—์„œ ์ˆ˜ํ–‰ํ•œ ์ฐจ๋ก€์˜ ํšŸ์ˆ˜๋ฅผ ์•Œ์•„๋‚ธ๋‹ค. ๊ฒŒ์ž„์ด ์‹œ์ž‘๋˜๋ฉด numberOfTurns ํ”„๋กœํผํ‹ฐ๋ฅผ 0์œผ๋กœ ์žฌ์„ค์ •ํ•˜๊ณ , ์ƒˆ๋กœ์šด ํ„ด์ด ์‹œ์ž‘๋˜๋ฉด ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋ฉฐ ๊ฒŒ์ž„์ด ๋๋‚˜๋ฉด ์ด ํ„ด ์ˆ˜๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

์œ„ ์ฝ”๋“œ์— ์žˆ๋Š” gameDidStart(_: )๊ตฌ๋ฌธ์€ game๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”Œ๋ ˆ์ดํ•˜๋ ค๋Š” ๊ฒŒ์ž„์— ๋Œ€ํ•œ ์ด๋ถ€ ์†Œ๊ฐœ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. game ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” SnakesAndLadders๊ฐ€ ์•„๋‹Œ DiceGameํƒ€์ž…์ด๋ฏ€๋กœ,gameDidStart(_: )๋Š” DiceGameํ”„๋กœํ† ์ฝœ์˜ ์ผ๋ถ€๋กœ ๊ตฌํ˜„๋œ ๋ฉ”์„œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ์—๋งŒ ์ ‘๊ทผํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฉ”์„œ๋“œ๋Š” ์—ฌ์ „ํžˆ ํƒ€์ž… ์บ์ŠคํŒ…์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ ์ธ์Šคํ„ด์Šค ํ˜•์‹์„ ์ฟผ๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ๊ฒŒ์ž„์ด ์ข…๋ฃŒ๋˜๋ฉด back ๋‹จ์—์„œ SnakeAndLadders ์ธ์Šคํ„ด์Šค์ธ์ง€ ํ™•์ธํ•˜๊ณ  ๊ทธ๋ ‡๋‹ค๋ฉด ์ ์ ˆํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

gameDidSet(: )๋ฉ”์„œ๋“œ๋Š” ์ „๋‹ฌ๋œ game ๋งค๊ฐœ๋ณ€์ˆ˜์˜ dice ํ”„๋กœํผํ‹ฐ์—๋„ ์ ‘๊ทผํ•œ๋‹ค. game ์€ DiceGame ํ”„๋กœํ† ์ฝœ์„ ๊ด€๊ณ„ ์—†์ด ์ค€์ˆ˜ํ•˜๋ฏ€๋กœ dice ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— gameDidStart( _:) ๋ฉ”์„œ๋“œ๋Š” ์–ด๋–ค ์ข…๋ฅ˜์˜ ๊ฒŒ์ž„์ด ํ”Œ๋ ˆ์ด๋˜๋Š”์ง€ ์ƒ๊ด€ ์—†์ด dice์˜ side ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜์—ฌ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋‹ค*.*

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 (6-๋ฉด์ฒด ์ฃผ์‚ฌ์œ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ์ž„์ž„)
// Rolled a 3 (3์ด ๋‚˜์˜ด)
// Rolled a 5 (5๊ฐ€ ๋‚˜์˜ด)
// Rolled a 4 (4๊ฐ€ ๋‚˜์˜ด)
// Rolled a 5 (5๊ฐ€ ๋‚˜์˜ด)
// The game lasted for 4 turns (๊ฒŒ์ž„์„ 4ํ„ด ๋™์•ˆ ์ง€์†ํ•จ)

 

ํ™•์žฅ์œผ๋กœ ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐ (Adding Protocol Conformance within an extension)

๊ธฐ์กด ํƒ€์ž…์˜ ์†Œ์Šค์ฝ”๋“œ์—์„œ๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—, ๊ธฐ์กด ํƒ€์ž…์˜ extension์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด protocol์„ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.

extension์€ ๊ธฐ์กด ํƒ€์ž…์— ์ƒˆ๋กœ์šด ํ”„๋กœํผํ‹ฐ, ๋ฉ”์„œ๋“œ, ์„œ๋ธŒ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ”„๋กœํ† ์ฝœ์ด ์š”๊ตฌํ•˜๋Š” ๊ฒƒ๋„ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

โ–ถ๏ธ Note

ํƒ€์ž…์˜ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค์—๋„ ํ•ด๋‹น ํƒ€์ž…์˜ extension์— ์˜ํ•ด ํ”„๋กœํ† ์ฝœ์ด ์ฑ„ํƒ ๋˜๋ฉด ์ž๋™์œผ๋กœ ๋ฐ˜์˜๋œ๋‹ค.

 

์˜ˆ๋ฅผ๋“ค์–ด ์•„๋ž˜์—์„œ ์˜ˆ์‹œ๋กœ ๋ณด์—ฌ์ค€ TextRepresentable์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์€ ํ…์ŠคํŠธ๋กœ ํ‘œํ˜„๋˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š” ๋ชจ๋“  ํƒ€์ž…์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœํ† ์ฝœ์ด๋‹ค. ์ด๋Š” ์ž์‹ ์— ๋Œ€ํ•œ ์„ค๋ช… ํ˜น์€ ํ˜„์žฌ ์ƒํƒœ์— ๋Œ€ํ•œ ํ…์ŠคํŠธ ์ผ ์ˆ˜ ์žˆ๊ฒ ๋‹ค.

protocol TextRepresentable {
  var textualDescription: String { get }
}

์œ„์— ์žˆ๋Š” Dice ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜์—ฌ TextRepresentable ์„ ์ฑ„ํƒํ•ด๋ณด์ž.

extension Dice: TextRepresentable {
  var textualDescription: String {
    return "A \\(sides)-sided dice"
  }
}

์ด extension์€ ๋งˆ์น˜ Dice๊ฐ€ ์ž์‹ ์˜ ์›๋ณธ ๊ตฌํ˜„์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค. ํ”„๋กœํ† ์ฝœ ์ด๋ฆ„์€ ํƒ€์ž… ๋’ค์— ์ฝœ๋ก (:)์„ ์ด์šฉํ•˜์—ฌ ์ž‘์„ฑํ•˜๋ฉด ๋˜๊ณ , ํ”„๋กœํ† ์ฝœ์˜ ๋ชจ๋“  ์š”๊ตฌ์‚ฌํ•ญ์€ ํ•ด๋‹น extension์˜ ์ค‘๊ด„ํ˜ธ ์•ˆ์—์„œ ์ •์˜ํ•˜๋ฉด ๋œ๋‹ค. ์ด์ œ ๋ชจ๋“  Dice์ธ์Šคํ„ด์Šค๋ฅผ TextRepresentable๋กœ๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.!!

let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription)
// "A 12-sided dice" ๋ฅผ ์ธ์‡„ํ•จ

์ด์™€ ๋น„์Šทํ•˜๊ฒŒ SnakesAndLadders ํด๋ž˜์Šค๋„ TextRepresentable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ณ  ์ค€์ˆ˜ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

extension SnakesAndLadders: TextRepresentable {
  var textualDescription: String {
    return "A game of Snakes and Ladders with \\(finalSquare) squares"
  }
}
print(game.textualDescription)
// "A game of Snakes and Ladders with 25 squares" ๋ฅผ ์ธ์‡„ํ•จ

 

์กฐ๊ฑด์— ๋”ฐ๋ผ ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜ํ•˜๊ธฐ

์ œ๋„ค๋ฆญ ํƒ€์ž…์€ ์ œ๋„ค๋ฆญ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ฐ™์€ ์กฐ๊ฑด์—์„œ๋งŒ ํ”„๋กœํ† ์ฝœ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํƒ€์ž…์— extension์„ ์‚ฌ์šฉํ• ๋•Œ ์ œ์•ฝ์กฐ๊ฑด์„ ๋‚˜์—ดํ•˜์—ฌ ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด ์กฐ๊ฑด๋ถ€๋กœ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค. where ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฑ„ํƒํ•˜๋ ค๋Š” ํ”„๋กœํ† ์ฝœ ์ด๋ฆ„๋’ค์— ์ œ์•ฝ์กฐ๊ฑด์„ ์ž‘์„ฑํ•˜๋ฉด ๋˜๋Š”๋ฐ, where ์ ˆ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ๋‹ค์Œ ์„น์…˜ chap.23 Generic ์„ ์ฐธ๊ณ ํ•ด๋ณด์ž

๋‹ค์Œ extension์€ ์ €์žฅํ•œ ์›์†Œ์˜ ํƒ€์ž…์ด TextRepresentable ์„ ์ค€์ˆ˜ํ•  ๋•Œ๋งˆ๋‹ค Array ์ธ์Šคํ„ด์Šค๊ฐ€ TextRepresentable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ฒŒ ํ•œ๋‹ค.

extension Array: TextRepresentable where Element: TextRepresentable {
  var textualDescription: String {
    let itemsAsText = self.map { $0.textualDescription }
    return "[" + itemsAsText.joined(separator: ", ") + "]"
  }
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// "[A 6-sided dice, A 12-sided dice]" ๋ฅผ ์ธ์‡„ํ•จ

 

ํ™•์žฅ์œผ๋กœ ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ ์„ ์–ธํ•˜๊ธฐ

ํƒ€์ž…์ด ํ”„๋กœํ† ์ฝœ์˜ ๋ชจ๋“  ํ•„์ˆ˜์กฐ๊ฑด์„ ์ด๋ฏธ ์ค€์ˆ˜ํ•˜๊ณ  ์žˆ์ง€๋งŒ, ๊ทธ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๊ณ  ์•„์ง ์•Œ๋ฆฌ์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ผ๋ฉด ๋นˆ extension์œผ๋กœ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

struct Hamster {
  var name: String
  var textualDescription: String {
    return "A hamster named \\(name)"
  }
}
extension Hamster: TextRepresentable {}

let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)
// "A hamster named Simon" ์„ ์ธ์‡„ํ•จ

ํ”„๋กœํ† ์ฝœ์˜ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•œ๋‹ค๊ณ  ํ•ด์„œ ํƒ€์ž…์ด ์ด๋ฅผ ์ž๋™์œผ๋กœ ์ฑ„ํƒํ•˜์ง„ ์•Š๋Š”๋‹ค. ๋ฐ˜๋“œ์‹œ ์ž์‹ ์ด ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.


 

Adopting a Protocol Using a Synthesized Implementation (ํ†ตํ•ฉ ๊ตฌํ˜„์„ ์จ์„œ ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒํ•˜๊ธฐ)

์Šค์œ„ํ”„ํŠธ๋Š” ๋งŽ์€ ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ์— Equatable, Hashable ๋ฐ Comparable์— ๋Œ€ํ•œ ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜์„ฑ์„ ์ž๋™์œผ๋กœ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฐ ํ†ตํ•ฉ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šค์Šค๋กœ ํ”„๋กœํ† ์ฝœ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํš์ผ๋œ ์ฝ”๋“œ๋ฅผ ๋ฐ˜๋ณต ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ๊ฑธ ์˜๋ฏธํ•œ๋‹ค.

โ–ถ๏ธ Equatable ํ†ตํ•ฉ ๊ตฌํ˜„

์Šค์œ„ํ”„ํŠธ๋Š” ๋‹ค์Œ ์ข…๋ฅ˜์˜ ์‚ฌ์šฉ์ž ์ •์˜ ํƒ€์ž…์— ๋Œ€ํ•ด์„œ Equatable Synthesized Implementation์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Equatable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋งŒ ์žˆ๋Š” ๊ตฌ์กฐ์ฒด
  • Equatable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” associated type ๋งŒ ์žˆ๋Š” ์—ด๊ฑฐํ˜•
  • associated type์ด ์—†๋Š” ์—ด๊ฑฐํ˜•

== ์˜ ํ†ตํ•ฉ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด == ์—ฐ์‚ฐ์ž๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ๋ง๊ณ  ์ฝ”๋“œ์— Equatable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค. Euatalbe ํ”„๋กœํ† ์ฝœ์€ !=์˜ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•œ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋Š” Vector2D ๊ตฌ์กฐ์™€ ์œ ์‚ฌํ•œ 3์ฐจ์› ์œ„์น˜ ๋ฒกํ„ฐ (x,y,z)์— ๋Œ€ํ•œ Vector 3D ๊ตฌ์กฐ์ฒด๋ฅผ ์ •์˜ํ•œ ์ฝ”๋“œ์ด๋‹ค. x,y,z ํ”„๋กœํผํ‹ฐ ๋ชจ๋‘ Equatable ํƒ€์ž…์ด๋ฏ€๋กœ Vector3D๋Š” ==์—ฐ์‚ฐ์ž์˜ ํ†ตํ•ฉ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

struct Vector3D: Equatable {
  var x = 0.0, y = 0.0, z = 0.0
}

let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
  print("These two vectors are also equivalent.")
}
// "These two vectors are also equivalent." ๋ฅผ ์ธ์‡„ํ•จ

 

โ–ถ๏ธ Hashable ํ†ตํ•ฉ ๊ตฌํ˜„

์Šค์œ„ํ”„ํŠธ๋Š” ๋‹ค์Œ ์ข…๋ฅ˜์˜ ์‚ฌ์šฉ์ž ์ •์˜ ํƒ€์ž…์—์„œ Hashable ํ†ตํ•ฉ ๊ตฌํ˜„์„ ์ œ๊ณตํ•œ๋‹ค.

  • Hashable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋งŒ ์žˆ๋Š” ๊ตฌ์กฐ์ฒด
  • Hashable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” associated type ๋งŒ ์žˆ๋Š” ์—ด๊ฑฐํ˜•
  • associated type์ด ์—†๋Š” ์—ด๊ฑฐํ˜•

hash(into: )์˜ ํ†ตํ•ฉ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, hash(into: )๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ์— Hashable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด ๋œ๋‹ค.

์Šค์œ„ํ”„ํŠธ๋Š” raw Value๊ฐ€ ์—†๋Š” ์—ด๊ฑฐํ˜•์— ๋Œ€ํ•ด Comparable์˜ ํ†ตํ•ฉ ๊ตฌํ˜„์„ ์ œ๊ณตํ•œ๋‹ค. ์—ด๊ฑฐํ˜•์— associated ํƒ€์ž…์ด ์žˆ๋‹ค๋ฉด ์ด๋“ค์€ ๋ชจ๋‘ ๋ฐ˜๋“œ์‹œ Comparable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•ด์•ผํ•œ๋‹ค.

<์˜ ํ†ตํ•ฉ ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, < ์—ฐ์‚ฐ์ž๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ์›๋ž˜ ์—ด๊ฑฐํ˜•์ด ์„ ์–ธ๋œ ์ฝ”๋“œ์— Comparable ํ”„๋กต์ฝœ์„ ์ฑ„ํƒํ•˜๋ฉด ๋œ๋‹ค. Comparealbe ํ”„๋กœํ† ์ฝœ์˜ ๊ธฐ๋ณธ๊ตฌํ˜„์ธ <=, > >=๋Š” ๋‚˜๋จธ์ง€ ๋น„๊ต์—ฐ์‚ฐ์ž๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋Š” beginner, intermediate, expert ์ผ€์ด์Šค๋ฅผ ๊ฐ–๋Š” SkillLevel ์—ด๊ฑฐํ˜•์„ ์ •์˜ํ•œ ์ฝ”๋“œ์ด๋‹ค. expert๋Š” ๋ณด์œ ํ•œ ๋ณ„์˜ ์ˆ˜์— ๋”ฐ๋ผ ์ถ”๊ฐ€๋กœ ์ˆœ์œ„๊ฐ€ ๋งค๊ฒจ์ง„๋‹ค.

enum SkillLevel: Comparable {
  case beginner
  case intermediate
  case expert(stars: Int)
}
var levels = [SkillLevel.intermediate, SkillLevel.beginner,
              SkillLevel.expert(stars: 5), SkillLevel.expert(stars: 3)]
for level in levels.sorted() {
  print(level)
}
// "beginner" ๋ฅผ ์ธ์‡„ํ•จ
// "intermediate" ๋ฅผ ์ธ์‡„ํ•จ
// "expert(stars: 3)" ๋ฅผ ์ธ์‡„ํ•จ
// "expert(stars: 5)" ๋ฅผ ์ธ์‡„ํ•จ

 

ํ”„๋กœํ† ์ฝœ ํƒ€์ž…์˜ ์ง‘ํ•ฉ์ฒด (collections)

์œ„์—์„œ ํƒ€์ž…์œผ๋กœ์จ์˜ ํ”„๋กœํ† ์ฝœ์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ, ๋ฐฐ์—ด์ด๋‚˜ ๋”•์…”๋„ˆ๋ฆฌ ๊ฐ™์€ ์ง‘ํ•ฉ์ฒด์— ์ €์žฅํ•  ํƒ€์ž…์œผ๋กœ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” TextRepresentable ๊ฒƒ๋“ค์˜ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•œ๋‹ค.

let things: [TextRepresentable] = [game, d12, simonTheHamster]

์ด์ œ ๋ฐฐ์—ด์˜ ํ•ญ๋ชฉ์„ ๋ฐ˜๋ณตํ•˜๊ณ , ๊ฐ ํ•ญ๋ชฉ์˜ ์„ค๋ช… ๋ฌธ์žฅ์„ ์ธ์‡„ํ•˜๋Š”๊ฒŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

for thing in things {
  print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares (์ •์‚ฌ๊ฐํ˜•์ด 25์นธ ์žˆ๋Š” ๋ฑ€๊ณผ ์‚ฌ๋‹ค๋ฆฌ ๊ฒŒ์ž„)
// A 12-sided dice (12-๋ฉด์ฒด ์ฃผ์‚ฌ์œ„)
// A hamster named Simon (์ด๋ฆ„์ด Simon ์ธ ํ–„์Šคํ„ฐ)

thing ์ƒ์ˆ˜์˜ ํƒ€์ž…์€ TextRepresentable ์ž„์„ ๊ธฐ์–ตํ•˜์ž. ์‹ค์ œ ์ธ์Šคํ„ด์Šค์˜ ์ด๋ฉด์ด Dice๋‚˜ DiceGame, Hamster ํƒ€์ž…์ธ ๊ฒฝ์šฐ์—๋„ ์ด ํƒ€์ž…๋“ค์ธ๊ฒŒ ์•„๋‹ˆ๊ณ  TextRepresentable ์ธ ๊ฒƒ์ด๋‹ค. ์‹ค์ œ๋กœ ๊ทธ๋Ÿฐ ํƒ€์ž…์ด๋”๋ผ๋„ ๋ชจ๋‘ TextRepresentable ํƒ€์ž…์ด๊ณ , ํ•ด๋‹น ํƒ€์ž…์—๋Š” textualDescription ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.


 

ํ”„๋กœํ† ์ฝœ ์ƒ์†

ํ”„๋กœํ† ์ฝœ์€ ํ•˜๋‚˜ ์ด์ƒ์˜ ๋‹ค๋ฅธ ํ”„๋กœํ† ์ฝœ์„ ์ƒ์†(inherit)ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ž์‹ ์ด ์ƒ์†ํ•œ ํ•„์ˆ˜ ์กฐ๊ฑด ์œ„์— ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๋” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ”„๋กœํ† ์ฝœ ์ƒ์† ๊ตฌ๋ฌธ์€ ํด๋ž˜์Šค ์ƒ์†๊ตฌ๋ฌธ๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ, ์˜ต์…˜์œผ๋กœ ์ƒ์†ํ•  ํ”„๋กœํ† ์ฝœ์ด ์—ฌ๋Ÿฌ๊ฐœ๋ผ๋ฉด ์‰ผํ‘œ(,) ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๋‹ค.

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
  // ํ”„๋กœํ† ์ฝœ ์ •์˜๋Š” ์—ฌ๊ธฐ์— ๋‘ 
}

์œ„์— ์žˆ๋Š” TextRepresentable ํ”„๋กตํ† ์ฝœ์„ ์ƒ์†ํ•œ ํ”„๋กœํ† ์ฝœ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž.

protocol PrettyTextRepresentable: TextRepresentable {
  var prettyTextualDescription: String { get }
}

์œ„ ์ฝ”๋“œ๋Š” PrettyTextRepresentable ์ด๋ผ๋Š” TextRepresentable์„ ์ƒ์†ํ•œ ์ƒˆ ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•œ๋‹ค. PrettyTextRepresentable๋ฅผ ์ฑ„ํƒํ•œ ์–ด๋–ค ๊ฒƒ์ด๋“  ๋ฐ˜๋“œ์‹œ TextRepresentable ์ด ๊ฐ•์ œ๋กœ ์ง€์ •ํ•œ ๋ชจ๋“  ํ•„์ˆ˜ ์กฐ๊ฑด๊ณผ, ๋”๋ถˆ์–ด์„œ PrettyTextRepresentable ์ด ์ถ”๊ฐ€ํ•œ ํ•„์ˆ˜์กฐ๊ฑด๊นŒ์ง€ ๋ชจ๋‘ ๋งŒ์กฑํ•ด์•ผํ•œ๋‹ค.

์ด ์ฝ”๋“œ์—์„œ๋Š” PrettyTextRepresentable๋Š” String์„ ๋ฐ˜ํ™˜ํ•˜๋Š” prettyTextualDescription์ด๋ผ๋Š” gettable ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ณตํ•˜๋ผ๋Š” ๋‹จ์ผ ํ•„์ˆ˜์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ์ƒ์„ฑํ•œ ํ”„๋กœํ† ์ฝœ์„ SnakeAndLadders ํด๋ž˜์Šค์— extension์„ ํ™œ์šฉํ•˜์—ฌ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด๋ณด์ž.

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
  }
}

์ด ์ต์Šคํ…์…˜์€ SnakesAndLadders ํƒ€์ž…์ด PrettyTextRepresentable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๋Š” ๊ฑธ ์•Œ๋ฆฌ๋ฉฐ ์ด๋ฅผ ์œ„ํ•ด prettyTextualDescription ํ”„๋กœํผํ‹ฐ์˜ ๊ตฌํ˜„์„ ์ œ๊ณตํ•œ๋‹ค๊ณ  ๋ช…์‹œํ•œ๋‹ค. PrettyTextRepresentable ํ”„๋กœ์ฝœ์—์„œ textualDescription ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๋ฉฐ ์‹œ์ž‘๋œ๋‹ค. ์ฝœ๋ก :๊ณผ ์ค„ ๋ฐ”๊ฟˆ\\n์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด๋ฅผ ์˜ˆ์œ ํ…์ŠคํŠธ ํ‘œํ˜„์˜ ์‹œ์ž‘์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋Ÿฐ ๋’ค board ๋ฐฐ์—ด์˜ square ๊ฐ’์„ ํ†ตํ•ด ๋„ํ˜•์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

  • ์ •์‚ฌ๊ฐํ˜• ๊ฐ’์ด 0 ๋ณด๋‹ค ํฌ๋ฉด, ์‚ฌ๋‹ค๋ฆฌ์˜ ๊ธฐ์ดˆ์ด๋ฏ€๋กœ, โ–ฒ ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • ์ •์‚ฌ๊ฐํ˜• ๊ฐ’์ด 0 ๋ณด๋‹ค ์ž‘์œผ๋ฉด, ๋ฑ€์˜ ๋จธ๋ฆฌ์ด๋ฏ€๋กœ, โ–ผ ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ, ์ •์‚ฌ๊ฐํ˜• ๊ฐ’์€ 0 ์ด๊ณ , “์ž์œ  (free)” ์ •์‚ฌ๊ฐํ˜•์ด๋ผ, โ—‹ ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.

์ด์ œ prettyTextualDescriptoin ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค SnakesAndLadders ์ธ์Šคํ„ด์Šค์˜ ๊พธ๋ฐˆ ๋ฌธ์žฅ ์„ค๋ช…๋„ ์ธ์‡„ํ•  ์ˆ˜์žˆ๋‹ค.

print(game.prettyTextualDescription)
// A game of Snakes and Ladders with 25 squares:
// โ—‹ โ—‹ โ–ฒ โ—‹ โ—‹ โ–ฒ โ—‹ โ—‹ โ–ฒ โ–ฒ โ—‹ โ—‹ โ—‹ โ–ผ โ—‹ โ—‹ โ—‹ โ—‹ โ–ผ โ—‹ โ—‹ โ–ผ โ—‹ โ–ผ โ—‹

 

Class-only ํ”„๋กœํ† ์ฝœ

ํ”„๋กœํ† ์ฝœ ์ƒ์† ๋ชฉ๋ก์— AnyObject ํ”„๋กต์ฝ”ใ…—ใ„น์„ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ํ”„๋กœํ† ์ฝœ ์ฑ„ํƒ์„ ํด๋ž˜์Šคํƒ€์ž…์œผ๋กœ๋งŒ ์ œํ•œํ•  ์ˆ˜์žˆ๋‹ค. (๊ตฌ์กฐ์ฒด x, ์—ด๊ฑฐํ˜• x, class only)

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
  // ํด๋ž˜์Šค-์ „์šฉ ํ”„๋กœํ† ์ฝœ ์ •์˜๋Š” ์—ฌ๊ธฐ์— ๋‘ 
}

์ด ์ฝ”๋“œ์˜ SomeClassonlyProtocol์€ ํด๋ž˜์Šค ํƒ€์ž…๋งŒ ์ฑ„ํƒ ๊ฐ€๋Šฅํ•˜๋‹ค. SomeClassOnlyProtocol์„ ์ฑ„ํƒํ•˜๋ ค๋Š” ๊ตฌ์กฐ์ฒด ๋˜๋Š” ์—ด๊ฑฐํ˜• ์ •์˜๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์ปดํŒŒ์ผ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

โ–ถ๏ธ Note

๊ทธ ํ”„๋กœํ† ์ฝœ์˜ ํ•„์ˆ˜ ์กฐ๊ฑด์ด ์ •์˜ํ•œ ๋™์ž‘์ด ์ค€์ˆ˜ํƒ€์ž…์€ ๊ฐ’ ์˜๋ฏธ ๊ตฌ์กฐ๋ณด๋‹ค๋Š”, ์ฐธ์กฐ ์˜๋ฏธ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„๋‹ค๊ณ  ๊ฐ€์ • ๋˜๋Š” ์š”๊ตฌํ•  ๋•Œ class only ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ฐธ์กฐ ๋ฐ ๊ฐ’ ํƒ€์ž… ๊ตฌ์กฐ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์ด์ „ ์ฑ•ํ„ฐ chap.9 Structures and Classes ๋ฅผ ๋‹ค์‹œ๋ณด์ž.


 

ํ”„๋กœํ† ์ฝœ ํ•ฉ์„ฑ (Protocol Composition)

๋™์‹œ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…์„ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด ์œ ์šฉํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ํ”„๋กœํ† ์ฝœ composition์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ”„๋กœํ† ์ฝœ์„ ํ•˜๋‚˜์˜ ํ”„๋กœํ† ์ฝœ๋กœ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ”„๋กœํ† ์ฝœ composition์€ composition์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ํ”„๋กœํ† ์ฝœ์˜ ์š”๊ตฌ์‚ฌํ•ญ์ด ๊ฒฐํ•ฉ๋œ ์ž„์‹œ ๋กœ์ปฌ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ์ž‘๋™ํ•œ๋‹ค. ํ”„๋กœํ† ์ฝœ composition์€ ์ƒˆ๋กœ์šด ํ”„๋กœํ† ์ฝœ ํƒ€์ž…์„ ์ •์˜ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

ํ”„๋กœํ† ์ฝœ composition์˜ ํ˜•์‹์€ SomProtocol & AnotherProtocol์ด๋‹ค. ์•ค๋“œ ๊ธฐํ˜ธ (&)๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•„์š”ํ•œ ๋งŒํผ ๋งŽ์€ ํ”„๋กœํ† ์ฝœ์„ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์‹ ์˜ ํ”„๋กœํ† ์ฝœ ๋ชฉ๋ก์— ๋”ํ•˜์—ฌ, ํ”„๋กœํ† ์ฝœ composition์€ ํด๋ž˜์Šคํƒ€์ž…๋„ ํ•˜๋‚˜ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์ˆ˜ ์ƒ์œ„ ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Named์™€ Aged๋ผ๋Š” ๋‘ ํ”„๋กœํ† ์ฝœ์„ ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ๋‹จ์ผ ํ”„๋กœํ† ์ฝœ composition ํ•„์ˆ˜ ์กฐ๊ฑด์œผ๋กœ ์กฐํ•ฉํ•œ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž.

protocol Named {
  var name: String { get }
}
protocol Aged {
  var age: Int { get }
}
struct Person: Named, Aged {
  var name: String
  var 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)
// "Happy birthday, Malcolm, you're 21!" ๋ฅผ ์ธ์‡„ํ•จ

โ–ถ๏ธ ์ฝ”๋“œ ์„ค๋ช…

  • Named ํ”„๋กœํ† ์ฝœ
    • Named ํ”„๋กœํ† ์ฝœ์—๋Š” ๋‹จ์ผ ํ•„์ˆ˜ ์กฐ๊ฑด์œผ๋กœ name์ด๋ผ๋Š” gettable String ์†์„ฑ์ด ์žˆ๋‹ค.
    • Person์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๊ฐ€ ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฑ„ํƒํ•œ๋‹ค.
  • Aged ํ”„๋กœํ† ์ฝœ
    • Aged ํ”„๋กœํ† ์ฝœ์—๋Š” ๋‹จ์ผ ํ•„์ˆ˜ ์กฐ๊ฑด์œผ๋กœ age๋ผ๋Š” gettable Int ์†์„ฑ์ด ์žˆ๋‹ค.
    • Person์ด๋ผ๋Š” ๊ตฌ์กฐ์ฒด๊ฐ€ ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฑ„ํƒํ•œ๋‹ค.
  • wishHappyBirthday(to:) ๋ฉ”์„œ๋“œ
    • celebrator ๋ผ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ : Named & Agedํƒ€์ž…. ์ฆ‰ Named ์™€ Aged ํ”„๋กœํ† ์ฝœ์„ ๋‘˜ ๋‹ค ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž….
    • ๋‘ ํ”„๋กœํ† ์ฝœ์„ ๋ชจ๋‘ ์ค€์ˆ˜ํ•˜๋Š” ํ•œ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•œ ํŠน์ • ํƒ€์ž…์ด ์–ด๋Š๊ฒƒ์ธ์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค.
  • birthdayPerson ์ด๋ผ๋Š” Person ์ธ์Šคํ„ด์Šค
    • wishHappyBirthday(to: ) ํ•จ์ˆ˜์— ์ด ์ธ์Šคํ„ด์Šค ์ „๋‹ฌ
    • Person ์ด ๋‘ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ํ˜ธ์ถœ์ด ์œ ํšจํ•˜๊ณ , wishHappyBirthday(to: )ํ•จ์ˆ˜๊ฐ€ ์ž์‹ ์˜ ์ƒ์ผ ์ธ์‚ฌ๋ง์„ ์ธ์‡„ํ•œ๋‹ค.

์ด์ „ ์˜ˆ์ œ์˜ Named ํ”„๋กœํ† ์ฝœ๊ณผ Location ํด๋ž˜์Šค๋ฅผ ์กฐํ•ฉํ•œ ์˜ˆ์ œ๋ฅผ ๋ณด์ž.

class Location {
  var latitude: Double
  var longitude: Double
  init(latitude: Double, longitude: Double) {
    self.latitude = latitude
    self.longitude = longitude
  }
}
class City: Location, Named {
  var name: String
  init(name: String, latitude: Double, longitude: Double) {
    self.name = name
    super.init(latitude: latitude, longitude: longitude)
  }
}
func beginConcert(in location: Location & Named) {
  print("Hello, \\(location.name)!")
}

let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)
beginConcert(in: seattle)
// "Hello, Seattle!" ๋ฅผ ์ธ์‡„ํ•จ

โ–ถ๏ธ ์ฝ”๋“œ ์„ค๋ช…

beginConcert(in: ) ํ•จ์ˆ˜๊ฐ€ ์ทจํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…์€ Location & Named ์ธ๋ฐ, ์ด๋Š” Location ํ•˜์œ„ ํด๋ž˜์Šค์ด๋ฉด์„œ, Named ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ์–ด๋–ค ํƒ€์ž…์ด๋ผ๋Š” ๋œป์ด๋‹ค. ์ด ๊ฒฝ์šฐ City๋Š” ํ•„์ˆ˜์กฐ๊ฑด ๋‘˜ ๋‹ค๋ฅผ ๋งŒ์กฑํ•œ๋‹ค.

beginConcert(in: ) ํ•จ์ˆ˜์— birthdayPerson์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ๋ฌดํšจํ™” ๋˜๋Š”๋ฐ, Person ์€ Location์˜ ํ•˜์œ„ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋–„๋ฌธ์ด๋‹ค~

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Location์˜ ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, Named ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ทธ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  beginConcert(in: )์„ ํ˜ธ์ถœํ•˜๋Š”๊ฒƒ๋„ ๋ฌดํšจํ™” ๋œ๋‹ค.


 

ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜์„ฑ ๊ฒ€์‚ฌํ•˜๊ธฐ

์ด์ „์„น์…˜์ธ Chap.19 type casting ์—์„œ ์„ค๋ช…ํ•œ is, as ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ณ , ํŠน์ • ํ”„๋กœํ† ์ฝœ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ”„๋กœํ† ์ฝœ ๊ฒ€์‚ฌ ๋ฐ ๋ณ€ํ™˜์€ ํƒ€์ž… ๊ฒ€์‚ฌ ๋ฐ ๋ณ€ํ™˜๊ณผ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ผํ•œ ๊ตฌ๋ฌธ์„ ๋”ฐ๋ฅธ๋‹ค.

  • is ์—ฐ์‚ฐ์ž๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋ฉด true ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • as? ๋ฒ„์ „์˜ ๋‚ด๋ฆผ ๋ณ€ํ™˜ ์—ฐ์‚ฐ์ž๋Š” ํ”„๋กœํ† ์ฝœ ํƒ€์ž…์˜ ์˜ต์…”๋„ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ทธ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์ด ๊ฐ’์ด nil ์ด๋‹ค.
  • as! ๋ฒ„์ „์˜ ๋‚ด๋ฆผ ๋ณ€ํ™˜ ์—ฐ์‚ฐ์ž๋Š” ํ”„๋กœํ† ์ฝœ ํƒ€์ž…์œผ๋กœ ๊ฐ•์ œ๋กœ ๋‚ด๋ฆผ ๋ณ€ํ™˜ํ•˜๋ฉฐ ๋‚ด๋ฆผ ๋ณ€ํ™˜์ด ์„ฑ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด ์‹คํ–‰ ์‹œ๊ฐ„ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋Š” ๋‹จ์ผ ์†์„ฑ ํ•„์ˆ˜ ์กฐ๊ฑด์œผ๋กœ, area๋ผ๋Š” gettable Double ์†์„ฑ์„ ๊ฐ€์ง„ HasArea ๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ •์˜ํ•œ ๊ฒƒ์ด๋‹ค.

protocol HasArea {
  var area: Double { get }
}

Circle๊ณผ Country๋ผ๋Š” ๋‘ ํด๋ž˜์Šค ๋ชจ๋‘ HasArea ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•œ๋‹ค.

class Circle: HasArea {
  let pi = 3.1415927
  var radius: Double
  var area: Double { return pi * radius * radius }
  init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
  var area: Double
  init(area: Double) { self.area = area }
}

โ–ถ๏ธ ์ฝ”๋“œ ์„ค๋ช…

  • Circle ํด๋ž˜์Šค
    • radius ์ €์žฅ ํ”„๋กœํผํ‹ฐ์— ๊ธฐ์ดˆํ•œ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ๋กœ area์†์„ฑ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๊ตฌํ˜„ํ•œ๋‹ค.
  • Countryํด๋ž˜์Šค
    • ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋กœ ์ง์ ‘ areaํ•„์ˆ˜ ์กฐ๊ฑด์„ ๊ตฌํ˜„ํ•œ๋‹ค.
  • ๋‘ ํด๋ž˜์Šค ๋ชจ๋‘ HasArea ํ”„๋กœํ† ์ฝœ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ค€์ˆ˜ํ•œ๋‹ค.

Animal ์ด๋ผ๋Š” HasAreaํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜์ง€ ์•Š๋Š”!! ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•ด๋ณด์ž.

class Animal {
  var legs: Int
  init(legs: Int) { self.legs = legs }
}

Circle, Country, Animal ํด๋ž˜์Šค๋Š” ๊ธฐ์ดˆ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ชจ๋‘ ํด๋ž˜์Šค๋ผ์„œ, ์ €์žฅ ๊ฐ’ ํƒ€์ž…์ด AnyObject ์ธ ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š”๋ฐ ์„ธ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค ๋ชจ๋‘๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

let objects: [AnyObject] = [
  Circle(radius: 2.0),
  Country(area: 243_610),
  Animal(legs: 4)
]

Objects ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฐ์—ด ๊ธ€์ž ๊ฐ’์€ ๋ฐ˜์ง€๋ฆ„์ด 2์ธ Circle ์ธ์Šคํ„ด์Šค, ์ œ๊ณฑ ํ‚ค๋กœ๋ฏธํ„ฐ ๋‹จ์œ„์˜ ์˜๊ตญ ๊ตญํ†  ๋ฉด์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ Country ์ธ์Šคํ„ด์Šค, ๋„ค ๋ฐœ ๋‹ฌ๋ฆฐ Animal ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ด๊ณ ์žˆ๋‹ค.

์ด์ œ objects ๋ฐฐ์—ด์„ ๋ฐ˜๋ณตํ•˜๊ณ , ๋ฐฐ์—ด ์•ˆ์˜ ๊ฐ ๊ฐ์ฒด๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ HasArea ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

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

โ–ถ๏ธ ์ฝ”๋“œ ์„ค๋ช…

๋ฐฐ์—ด ์•ˆ์˜ ๊ฐ์ฒด๊ฐ€ HasArea ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•  ๋•Œ๋งˆ๋‹ค as? ์—ฐ์‚ฐ์ž๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์˜ต์…”๋„ ๊ฐ’์„ ์˜ต์…”๋„ ์—ฐ๊ฒฐ๋กœ ํ’€๊ณ  objectWithArea๋ผ๋Š” ์ƒ์ˆ˜์— ๋„ฃ๋Š”๋‹ค. objectWithArea ์ƒ์ˆ˜ ํƒ€์ž…์€ HasArea์ž„์„ ์•Œ๊ณ  ์žˆ์–ด์„œ, ์ž์‹ ์˜ area ์†์„ฑ์— ํƒ€์ž…-์•ˆ์ „ํ•˜๊ฒŒ ์ ‘๊ทผํ•˜๊ณ  ์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋‹ค.

casting(๋ณ€ํ™˜)๊ณผ์ •์—์„œ ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์€ ์•„๋‹˜์„ ๊ธฐ์–ตํ•˜์ž. ์ด๋“ค์€ ๊ณ„์† Circle, Country, Animal ์ด๋‹ค. ํ•˜์ง€๋งŒ objectWithArea ์ƒ์ˆ˜์— ์ €์žฅํ•œ ์‹œ์ ์—๋Š” ํƒ€์ž…์ด HasArea๋ผ๋Š” ๊ฒƒ๋งŒ ์•Œ์•„์„œ, ์ž์‹ ์˜ area ์†์„ฑ์—๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ ํ•˜๋‹ค.


 

์˜ต์…”๋„ ํ”„๋กœํ† ์ฝœ ํ•„์ˆ˜ ์กฐ๊ฑด

ํ”„๋กœํ† ์ฝœ์„ ์œ„ํ•œ ์˜ต์…”๋„ ํ•„์ˆ˜ ์กฐ๊ฑด์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํ•„์ˆ˜์กฐ๊ฑด๋“ค์€, ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…์ด ๊ตฌํ˜„๋˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ‘์˜ต์…”๋„ ํ•„์ˆ˜ ์กฐ๊ฑด'์€ ํ”„๋กœํ† ์ฝœ ์ •์˜์—์„œ ์ ‘๋‘์‚ฌ๋กœ ‘optional’ ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ธ๋‹ค. ‘์˜ต์…”๋„ ํ•„์ˆ˜์กฐ๊ฑด'์€ objective-c ์™€ ์ƒํ˜ธ ํ˜ธํ™˜๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ์‚ฌ์šฉ๋œ๋‹ค. ‘ํ”„๋กœํ† ์ฝœ'๊ณผ ‘์˜ต์…”๋„ ํ•„์ˆ˜์กฐ๊ฑด'์€ ๋‘˜ ๋‹ค ๋ฐ˜๋“œ์‹œ ‘@objc’ ํŠน์„ฑ์„ ํ‘œ์‹œํ•ด์•ผํ•œ๋‹ค. objective-cํด๋ž˜์Šค๋‚˜ ๋‹ค๋ฅธ @objc ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•œ ํด๋ž˜์Šค๋งŒ์ด ‘@objc ํ”„๋กœํ† ์ฝœ'์„ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž. ๊ตฌ์กฐ์ฒด๋‚˜ ์—ด๊ฑฐํ˜•์€ ์ด๋ฅผ ์ฑ„ํƒํ•  ์ˆ˜ ์—†๋‹ค.

‘์˜ต์…”๋„ ํ•„์ˆ˜ ์กฐ๊ฑด'์—์„œ ๋ฉ”์„œ๋“œ๋‚˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ๊ทธ ํƒ€์ž…์€ ์ž๋™์œผ๋กœ ‘์˜ต์…”๋„’์ด ๋œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด **(Int) -> String** ํƒ€์ž…์˜ ๋ฉ”์„œ๋“œ๋Š” **((Int) -> String)?** ์ด ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜๊ฐ’์ด ์•„๋‹ˆ๋ผ, ‘์ „์ฒด ํ•จ์ˆ˜ ํƒ€์ž…'์„ ์˜ต์…”๋„๋กœ ํฌ์žฅํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž.

‘์˜ต์…”๋„ ํ”„๋กœํ† ์ฝœ ํ•„์ˆ˜ ์กฐ๊ฑด'์€ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…์ด ํ•„์ˆ˜ ์กฐ๊ฑด์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์„ ์œ„ํ•ด ‘์˜ต์…”๋„ ์ฒด์ด๋‹'์„ ๊ฐ€์ง€๊ณ  ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. someOptionalMethod?(someArgument)์™€ ๊ฐ™์ด ํ˜ธ์ถœ๋  ๋•Œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๋’ค์— ๋ฌผ์Œํ‘œ๋ฅผ ๋„ฃ์–ด ์˜ต์…”๋„ ๋ฉ”์„œ๋“œ์˜ ๊ตฌํ˜„์„ ํ™•์ธํ•œ๋‹ค. (์˜ต์…”๋„ ์ฒด์ด๋‹์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์ด์ „ ์„น์…˜ chap.16 ์„ ํ™•์ธํ•˜์ž.)

๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ increment(์ฆ๊ฐ€๋Ÿ‰)๋ฅผ ์ œ๊ณตํ•˜๋Š” Counter๋ผ๋Š” ์ •์ˆ˜ ๊ณ„์‚ฐ class๋ฅผ ์ •์˜ํ•  ๊ฒƒ์ด๋‹ค. ์ด ๋ฐ์ดํ„ฐ ์†Œ์Šค๋Š” ๋‘ ๊ฐ€์ง€ ์„ ํƒ์  ์š”๊ตฌ์‚ฌํ•ญ์ด ์žˆ๋Š” CounterDataSource ํ”„๋กœํ† ์ฝœ์— ์˜ํ•ด ์ •์˜๋œ๋‹ค.

@objc protocol CounterDataSource {
  @objc optional func increment(forCount count: Int) -> Int
  @objc optional var fixedIncrement: Int { get }
}

CounterDataSource ํ”„๋กœํ† ์ฝœ์€ incremental(forCount:) ๋ผ๋Š” ‘์˜ต์…”๋„ ๋ฉ”์†Œ๋“œ ํ•„์ˆ˜ ์กฐ๊ฑด’ ๊ณผ fixedIncrement ๋ผ๋Š” ‘์˜ต์…”๋„ ์†์„ฑ ํ•„์ˆ˜ ์กฐ๊ฑด’ ์„ ์ •์˜ํ•œ๋‹ค. ์ด ํ•„์ˆ˜ ์กฐ๊ฑด๋“ค์€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ Count ์ธ์Šคํ„ด์Šค์— ์ ์ ˆํ•œ ์ฆ๊ฐ€๋Ÿ‰์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๋ฐฉ์‹์„ ์ •์˜ํ•œ๋‹ค.

โ–ถ๏ธ Note

์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด protocol ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ CounterDataSource protocol์„ ์ค€์ˆ˜ํ•˜๋Š” class๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ชจ๋‘ ์˜ต์…”๋„์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฌผ๋ก  ๊ตณ์ด ๊ทธ๋Ÿด ํ•„์š”๋Š” ์—†๋‹ค.

์•„๋ž˜์—์„œ ์ •์˜ํ•œ Counter ํด๋ž˜์Šค๋Š”, CounterDataSource? ํƒ€์ž…์˜ ‘์˜ต์…”๋„ dataSource ์†์„ฑ'์„ ๊ฐ€์ง„๋‹ค.

class Counter {
  var count = 0
  var dataSource: CounterDataSource?
  func increment() {
    if let amount = dataSource?.increment?(forCount: count) {
      count += amount
    } else if let amount = dataSource?.fixedIncrement {
      count += amount
    }
  }
}

โ–ถ๏ธ ์ฝ”๋“œ ์„ค๋ช…

  • Counter ํด๋ž˜์Šค
    • ํ˜„์žฌ ๊ฐ’์„ count ๋ผ๋Š” ๋ณ€์ˆ˜์— ์ €์žฅ
    • ๋งค ๋ฒˆ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค count ์†์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” increment ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜
  • increment() ๋ฉ”์„œ๋“œ
    • ์ฆ๊ฐ€๋Ÿ‰์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๋จผ์ € ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ๋Œ€ํ•œ incremental(forCount: )๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋๋Š”์ง€ ์ฐพ์œผ๋ ค๊ณ  ํ•œ๋‹ค.
    • increment()๋ฉ”์„œ๋“œ๋Š” increment(forCount; )ํ˜ธ์ถœ์„ ์‹œ๋„ํ•˜๊ธฐ ์œ„ํ•ด ‘์˜ต์…”๋„ ์ฒด์ด๋‹'์„ ์‚ฌ์šฉํ•˜๋ฉฐ ๋ฉ”์„œ๋“œ ๋‹จ์ผ์ธ์ž๋กœ ํ˜„์žฌ์˜ count ๊ฐ’์„ ์ „๋‹ฌํ•œ๋‹ค.
      • ์—ฌ๊ธฐ์—์„œ ์‚ฌ์šฉ๋œ optional ์ฒด์ด๋‹ ์„ค๋ช…
        1. dataSource๊ฐ€ nil์ผ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ, dataSource ๊ฐ€ nil์ด ์•„๋‹ ๋•Œ๋งŒ incremental(forCount: )๊ฐ€ ํ˜ธ์ถœ๋ผ์•ผ ํ•จ์„ ์ง€์‹œํ•˜๋„๋ก dataSource ๋’ค์— ?๋ฅผ ๋ถ™์ž„
        2. dataSource๊ฐ€ ์กด์žฌํ•  ์ง€๋ผ๋„, ์˜ต์…”๋„ ํ•„์ˆ˜ ์กฐ๊ฑด์ด๊ธฐ ๋•Œ๋ฌธ์— increment(forCount: )๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ๋ณด์žฅ์ด ์—†๋‹ค. ๋”ฐ๋ผ์„œ increment(forCount: )๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ๋„ ์˜ต์…”๋„ ์ฒด์ด๋‹์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋œ๋‹ค. increment(forCount:) ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์€ increment(forCount:) ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๊ฒƒ์ด increment(forCount:) ๋„ ์ด๋ฆ„ ๋’ค์— ๋ฌผ์Œํ‘œ๊ฐ€ ์žˆ๋Š” ์ด์œ ์ด๋‹ค.
      • ์ด๋Ÿฌํ•œ ๋‘ ๊ฐ€์ง€ ์ด์œ ๋กœ ์ธํ•ด increment(forCount: )ํ˜ธ์ถœ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ increment(forCount: )๋Š” ์˜ต์…”๋„ Int๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. increment(forCount: )๊ฐ€ CounterDataSource์˜ ์ •์˜์—์„œ ์˜ต์…”๋„์ด ์•„๋‹Œ Int๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋˜์–ด ์žˆ๋”๋ผ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. ๋‘ ๊ฐœ์˜ ์˜ต์…”๋„ ์ฒด์ด๋‹์ด ์ฐจ๋ก€๋Œ€๋กœ ์žˆ์ง€๋งŒ ๊ฒฐ๊ณผ๋Š” ํ•˜๋‚˜์˜ ์˜ต์…”๋„๋กœ ๋ž˜ํ•‘๋œ๋‹ค.
    • increment(forCount: )๋ฅผ ์ดˆ๋ฃจํ•œ ๋’ค ๋ฐ˜ํ™˜ํ•˜๋Š” ์˜ต์…”๋„ Int ๋Š” ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉ์„ ์‚ฌ์šฉํ•˜์—ฌ amount๋ผ๋Š” ์ƒ์ˆ˜๋กœ ๋ž˜ํ•‘ ํ•ด์ œ ๋œ๋‹ค. ์˜ต์…”๋„ Int ๊ฐ’์ด ์žˆ์œผ๋ฉด ๋ž˜ํ•‘ ๋˜์ง€ ์•Š์€ ๊ธˆ์•ก์ด count ํ”„๋กœํผํ‹ฐ์— ์ถ”๊ฐ€๋˜๊ณ  ์ฆ๊ฐ€๊ฐ€ ์™„๋ฃŒ๋œ๋‹ค.

dataSource๊ฐ€ nil์ด๊ฑฐ๋‚˜ increment(forCount:)๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„ increment(forCount:)์˜ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ increment() ๋ฉ”์„œ๋“œ๋Š” dataSource์˜ fixedIncrement ํ”„๋กœํผํ‹ฐ์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ•œ๋‹ค.  fixedIncrement ํ”„๋กœํผํ‹ฐ๋„ ์˜ต์…”๋„ ์š”๊ตฌ์‚ฌํ•ญ์ด๋ฏ€๋กœ ํ•ด๋‹น ๊ฐ’์ด  CounterDataSource protocol์—์„œ Int ํƒ€์ž…์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ๋”๋ผ๋„ ํ•ด๋‹น ๊ฐ’์€ ์˜ต์…”๋„ Int ํƒ€์ž…์ด๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋Š” dataSource๊ฐ€ ์ฟผ๋ฆฌ ๋  ๋•Œ๋งˆ๋‹ค ์ƒ์ˆ˜ ๊ฐ’ 3์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ„๋‹จํ•œ CounterDataSource ๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๋‹ค . ์ด๋Š” ์˜ต์…”๋„ ์š”๊ตฌ์‚ฌํ•ญ์ธ fixedIncrement ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

class ThreeSource: NSObject, CounterDataSource {
  let fixedIncrement = 3
}

ThreeSource์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ์šด Counter ์ธ์Šคํ„ด์Šค๋ฅผ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
  counter.increment()
  print(counter.count)
}
// 3
// 6
// 9
// 12

์œ„ ์ฝ”๋“œ๋Š” ์ƒˆ๋กœ์šด Counter ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ ์ƒˆ๋กœ์šด ThreeSource ์ธ์Šคํ„ด์Šค๋ฅผ ์„ค์ •ํ•˜๋ฉฐ, counter์˜ increment()๋ฉ”์„œ๋“œ๋ฅผ ๋„ค ๋ฒˆ ํ˜ธ์ถœํ•œ๋‹ค. Counter์˜ count ์†์„ฑ์€ increment()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค 3์”ฉ ์ฆ๊ฐ€ํ•œ๋‹ค.

๋‹ค์Œ์€ Counter์ธ์Šคํ„ด์Šค๋ฅผ ํ˜„์žฌ count๊ฐ’์—์„œ ‘0’์œผ๋กœ ์œ„๋กœ ์„ธ๊ฑฐ๋‚˜, ์•„๋ž˜๋กœ ์„ธ๋Š” TowardsZeroSource๋ผ๋Š” ์กฐ๊ธˆ ๋” ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค์ด๋‹ค.

class TowardsZeroSource: NSObject, CounterDataSource {
  func increment(forCount count: Int) -> Int {
    if count == 0 {
      return 0
    } else if count < 0 {
      return 1
    } else {
      return -1
    }
  }
}

TowardsZeroSourceํด๋ž˜์Šค๋Š” CounterDataSourceํ”„๋กœํ† ์ฝœ์— ์žˆ๋Š” ์˜ต์…”๋„ increment(forCount: )๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉฐ ์–ด๋Š ๋ฐฉํ–ฅ์œผ๋กœ ์…€์ง€ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด count ์ธ์ž ๊ฐ’์„ ์‚ฌ์šฉํ•œ๋‹ค. count๊ฐ€ ์ด๋ฏธ ‘0’์ด๋ฉด ๋” ์ด์ƒ ์„ธ์ง€ ๋ง์•„์•ผ ํ•จ์„ ์ง€์‹œํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”์„œ๋“œ๊ฐ€ 0์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

-4์—์„œ ‘0’๊นŒ์ง€ ์„ธ๊ธฐ ์œ„ํ•ด ๊ธฐ์กด Counter์ธ์Šคํ„ด์Šค์™€ TowardsZeroSource์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Counter๊ฐ€ ‘0’์— ๋‹ฟ์œผ๋ฉด ๋” ์ด์ƒ ์„ธ์ง€ ์•Š๋Š”๋‹ค.

counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
  counter.increment()
  print(counter.count)
}
// -3
// -2
// -1
// 0
// 0

 

Protocol Extensions (ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜)

ํ”„๋กœํ† ์ฝœ์€ ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž, ์„œ๋ธŒ ์Šคํฌ๋ฆฝํŠธ, ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ ๊ตฌํ˜„์„ ์ž์‹ ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์—๊ฒŒ ์ œ๊ณตํ•˜๋ ค๋ฉด extension์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ ํƒ€์ž…์˜ ์ ํ•˜์„ฑ, ์ „์—ญํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ํ”„๋กœํ† ์ฝœ ์ž์ฒด์— ๋Œ€ํ•œ ๋™์ž‘์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด, RandomNumberGenerator ํ”„๋กœํ† ์ฝœ์— extension์„ ์‚ฌ์šฉํ•˜์—ฌ randomBool() ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ํ•„์ˆ˜์ ์ธ random() ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž„์˜์˜ Bool ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

extension RandomNumberGenerator {
  func randomBool() -> Bool {
    return random() > 0.5
  }
}

ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•œ ์ต์Šคํ…์…˜์„ ์ƒ์„ฑํ•จ์œผ๋กœ์จ ๋ชจ๋“  ์ค€์ˆ˜ ํƒ€์ž…์€ ์–ด๋–ค ์ถ”๊ฐ€์ ์ธ ์ˆ˜์ • ์—†์ด๋„ ์ด randomBool() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

let generator = LinearCongruentialGenerator()
print("Here's a random number: \\(generator.random())")
// "Here's a random number: 0.3746499199817101" ๋ฅผ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค.
print("And here's a random Boolean: \\(generator.randomBool())")
// "And here's a random Boolean: true" ๋ฅผ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์€ ์ค€์ˆ˜ ํƒ€์ž…์— ๊ตฌํ˜„์„ ์ถ”๊ฐ€ํ•  ์ˆœ ์žˆ์ง€๋งŒ, ํ”„๋กœํ† ์ฝœ์„ ํ™•์žฅํ•˜๋„๋ก ๋งŒ๋“ค๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ํ”„๋กœํ† ์ฝœ์„ ์ƒ์†ํ•˜๊ฒŒ ํ•  ์ˆ˜๋Š” ์—†๋‹ค. ํ”„๋กœํ† ์ฝœ ์ƒ์†์€ ํ”„๋กœํ† ์ฝœ ์„ ์–ธ ๊ทธ ์ž์ฒด์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๊ธฐ๋ณธ ๊ตฌํ˜„ ์ œ๊ณตํ•˜๊ธฐ

ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์„ ์‚ฌ์šฉํ•ด์„œ ํ•ด๋‹น ํ”„๋กœํ† ์ฝœ์ด ์š”๊ตฌํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ ๋˜๋Š” ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์‹ ์„ ์ฑ„ํƒํ•œ ํƒ€์ž…์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ์ด๋ฏธ ๊ตฌํ˜„ํ•œ ๊ฒฝ์šฐ์—๋Š”, ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์—์„œ ๊ตฌํ˜„ํ•œ ๊ฒƒ ๋ง๊ณ  ํ•ด๋‹น ํƒ€์ž… ๋‚ด์—์„œ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด ์‚ฌ์šฉ๋œ๋‹ค.

โ–ถ๏ธ Note

์ต์Šคํ…์…˜์—์„œ ํ”„๋กœํ† ์ฝœ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ์˜ต์…”๋„ ํ”„๋กœํ† ์ฝœ ์š”๊ตฌ์‚ฌํ•ญ๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค. ์ฑ„ํƒํ•œ ํƒ€์ž…์ด ์ž์ฒด์ ์œผ๋กœ ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ตฌํ˜„ํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ, ์ด๋ฏธ ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์— ๊ตฌํ˜„์ด ๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ์˜ต์…”๋„ ์ฒด์ด๋‹ ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์˜ˆ๋ฅผ๋“ค์–ด, TextRepresentable ํ”„๋กœํ† ์ฝœ์„ ์ƒ์†ํ•˜๋Š” PrettyTextRepresentable ํ”„๋กœํ† ์ฝœ์€ prettyTextualDescription ํ”„๋กœํผํ‹ฐ์˜ default ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜์—ฌ ๋‹จ์ˆœํ•˜๊ฒŒ textualDescriptionํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

extension PrettyTextRepresentable {
  var prettyTextualDescription: String {
    return textualDescription
  }
}

 

ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์— Constraints (์ œ์•ฝ ์กฐ๊ฑด) ์ถ”๊ฐ€ํ•˜๊ธฐ

ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์„ ์ •์˜ํ•  ๋•Œ, ํ•ด๋‹น ํƒ€์ž…์ด ์ต์Šคํ…์…˜์˜ ๋ฉ”์„œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ์ „์— ์ถฉ์กฑํ•ด์•ผํ•˜๋Š” ์ œ์•ฝ์กฐ๊ฑด์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ œ๋„ค๋ฆญ where์ ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ extension์„ ์‚ฌ์šฉํ•  ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„ ๋’ค์— ์ œ์•ฝ์กฐ๊ฑด์„ ์ž‘์„ฑํ•  ์ˆ˜์žˆ๋‹ค. generic where์ ˆ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ฐ”๋กœ ๋‹ค์Œ์žฅ, chap.23 Generic Where Clauses ์—์„œ ๋ฐฐ์›Œ๋ณด์ž.

์˜ˆ๋ฅผ๋“ค์–ด Element๊ฐ€ Equatable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ๋ชจ๋“  ์ปฌ๋ ‰์…˜์—๋งŒ ์ ์šฉ๋˜๋Š” ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ปฌ๋ ‰์…˜์˜ element๋ฅผ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ผ๋ถ€์ธ Equatable ํ”„๋กœํ† ์ฝœ๋กœ ์ œํ•œํ•˜๋ฉด ==, != ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ Element๊ฐ„ ๋น„๊ต๋ฅผ ํ•  ์ˆ˜์žˆ๋‹ค.

extension Collection where Element: Equatable {
  func allEqual() -> Bool {
    for element in self {
      if element != self.first {
        return false
      }
    }
    return true
  }
}

allEqual() ๋ฉ”์„œ๋“œ๋Š” ์ปฌ๋ ‰์…˜์˜ ๋ชจ๋“  Element๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ์—๋งŒ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋‘ ๊ฐœ์˜ Int Array์— ์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด์ž. ํ•˜๋‚˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  Element๊ฐ€ ๋™์ผํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.

let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]

Int ํƒ€์ž…์€ Equatable์„ ์ค€์ˆ˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— equalNumbers, differentNumbers๋Š” allEqual() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

print(equalNumbers.allEqual())
// "true" ๋ฅผ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค.
print(differentNumbers.allEqual())
// "false" ๋ฅผ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค.

โ–ถ๏ธ Note

์–ด๋–ค ํƒ€์ž…์ด ๋™์ผํ•œ ๋ฉ”์„œ๋“œ, ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ œ์•ฝ๋œ extension์˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ฒฝ์šฐ Swift๋Š” ๊ฐ€์žฅ specialezed ํ•œ ์ œ์•ฝ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋ฐ˜์‘ํ˜•