์๋
ํ์ธ์, ๊ฐ์์
๋๋ค! (์..์ค๋๋ง์ ์ธ์ฌํ๋๊ฒ ๊ฐ์ง..)
์ผ์ฃผ์ผ๋ง์ ๋์์จ ๊ณต์ ๋ฌธ์ ์ ๋ฆฌ์
๋๋ค.. ์ด๋ฒ์ฃผ ๋ด๋ด ํ๋กํ ์ฝ ๊ด๋ จํด์๋ง ์ ๋ฆฌํ ๊ฒ ๊ฐ์์. ๊ทธ๋ฆฌ๊ณ ์ ํ์์นด๋ฐ๋ฏธ์ ์์์ผ๋ก ์๊ฐ์ด ๋๋ฌด๋๋ฌด ๋ถ์กฑํ๋ค์ ใ
ใ
๊ทธ๋๋ ์ง์น์ง๋ ์๊ณ ํ๋กํ ์ฝ ์ ๋ฆฌ๋ด์ฉ์ ๊ฐ์ ธ์์ต๋๋ค. ๋ด์ฉ์ด ๋~~~~~๋ฌด ๋ง์์,, ๋ชจ๋ ๋ด์ฉ์ด ๋ค ๋จธ๋ฆฟ์์ ๋ค์ด์ค์ง ์์ ๊ฒ๊ฐ์์ ใ
๋ ์ฝ์ด๋ณด๊ณ , ์ค๋ฌด์์ ์ ํด๋ณด๋ ๋ฐฉ๋ฒ ๋ฟ์ด๊ฒ์ฃ ? ๊ทธ๋ผ ์ฆ๊ฑฐ์ด ๋ง์์ผ๋ก ์์ํด๋ด
์๋ค! gogo
Swift Document chap.22 Protocols (ํ๋กํ ์ฝ) ๋ฐ๋ก๊ฐ๊ธฐ
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 ์ฒด์ด๋ ์ค๋ช
- dataSource๊ฐ nil์ผ ๊ฐ๋ฅ์ฑ์ด ์์ผ๋ฏ๋ก, dataSource ๊ฐ nil์ด ์๋ ๋๋ง incremental(forCount: )๊ฐ ํธ์ถ๋ผ์ผ ํจ์ ์ง์ํ๋๋ก dataSource ๋ค์ ?๋ฅผ ๋ถ์
- dataSource๊ฐ ์กด์ฌํ ์ง๋ผ๋, ์ต์ ๋ ํ์ ์กฐ๊ฑด์ด๊ธฐ ๋๋ฌธ์ increment(forCount: )๋ฅผ ๊ตฌํํ๋ค๋ ๋ณด์ฅ์ด ์๋ค. ๋ฐ๋ผ์ increment(forCount: )๊ฐ ๊ตฌํ๋์ด ์์ง ์์ ๊ฐ๋ฅ์ฑ๋ ์ต์ ๋ ์ฒด์ด๋์ ์ํด ์ฒ๋ฆฌ๋๋ค. increment(forCount:) ์ ๋ํ ํธ์ถ์ increment(forCount:) ๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ง ๋ฐ์ํ๋ค. ์ด๊ฒ์ด increment(forCount:) ๋ ์ด๋ฆ ๋ค์ ๋ฌผ์ํ๊ฐ ์๋ ์ด์ ์ด๋ค.
- ์ด๋ฌํ ๋ ๊ฐ์ง ์ด์ ๋ก ์ธํด increment(forCount: )ํธ์ถ์ด ์คํจํ ์ ์์ผ๋ฏ๋ก increment(forCount: )๋ ์ต์ ๋ Int๊ฐ์ ๋ฐํํ๋ค. increment(forCount: )๊ฐ CounterDataSource์ ์ ์์์ ์ต์ ๋์ด ์๋ Int๊ฐ์ ๋ฐํํ๋๋ก ๋์ด ์๋๋ผ๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ค. ๋ ๊ฐ์ ์ต์ ๋ ์ฒด์ด๋์ด ์ฐจ๋ก๋๋ก ์์ง๋ง ๊ฒฐ๊ณผ๋ ํ๋์ ์ต์ ๋๋ก ๋ํ๋๋ค.
- ์ฌ๊ธฐ์์ ์ฌ์ฉ๋ optional ์ฒด์ด๋ ์ค๋ช
- 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 ํ ์ ์ฝ์กฐ๊ฑด์ ํด๋นํ๋ ๊ตฌํ์ ์ฌ์ฉํ๋ค.