Extensions ์ ์ด๋ฏธ ์กด์ฌํ๋ class, structure, enumeration, protocol์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค.
Swift Extension์ผ๋ก ๊ฐ๋ฅํ ๊ฒ๋ค์ ๋ค์๊ณผ ๊ฐ๋ค.
- computed instance/type property ์ถ๊ฐ
- instance/type ๋ฉ์๋ ์ถ๊ฐ
- ์ด๋์ ๋ผ์ด์ ธ ์ถ๊ฐ
- ์ญ์คํฌ๋ฆฝํธ ์ถ๊ฐ
- ์๋ก์ด nested types ์ถ๊ฐ
- ํน์ ํ๋กํ ์ฝ์ ์ค์ํ๋๋ก ๊ธฐ๋ฅ ์ถ๊ฐ
์์๊ณผ ์ต์คํ ์
์ต์คํ ์ ์ ํ์ ์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ , ์ด๋ฏธ ์กด์ฌํ๋ ๊ธฐ๋ฅ์ ์ฌ์ ์ํ ์๋ ์๋ค. ์์์ ํด๋์ค์์๋ง ๊ฐ๋ฅํ์ง๋ง ์ต์คํ ์ ์ structure, class, protocol, generic ๋ฑ์์ ๊ฐ๋ฅํ๋ค.
extension ํ์ฅํ _ํ์
_์ด๋ฆ {
}extension ํค์๋๋ฅผ ์ฌ์ฉํ๋ค. ์๋ก์ด protocol์ ๋ฐ๋ฅด๋๋ก(conform) ์ถ๊ฐํ๊ณ ์ถ์ ๋์๋
extension ํ์ฅํ _ํ์
_์ด๋ฆ: ํ๋กํ ์ฝ_1, ํ๋กํ ์ฝ_2 {
// ํด๋น protocol๋ค์ ํ์ํ implementations
}- ํญ์ file scope์์๋ง ์ ์ธํ ์ ์๊ณ ,
- fileprivate(๋๋ private) ์ ๊ทผ์ ์ด์๋ฅผ ์ด์ฉํ์ฌ ํด๋น ํ์ผ ๋ด์์๋ง ์ ๊ทผ ๊ฐ๋ฅํ ํ๋กํผํฐ/๋ฉ์๋ ๋ฑ์ ์ถ๊ฐํ ์ ์๋ค. *global variable/constant๋ก ์ ์ธ๋ ๊ฒฝ์ฐ private์ fileprivate๋ ๋์ผํ๊ฒ ๋์
- ์๋ ํ์ ์ fileprivate/private๋ก ์ ์ธ๋ ํ๋กํผํฐ์ ์ ๊ทผํ ์๋ ์๋ค. ํ์ง๋ง private๋ก ์ ์ธ๋ ๊ฒฝ์ฐ์ ํํด์๋ง, ์๋ ํ์ ์ด ์ ์๋ ํ์ผ๊ณผ ๋์ผํ ํ์ผ์ ์์นํ ๊ฒฝ์ฐ์ extension์์ ํด๋น Property์ ์ ๊ทผํ ์ ์๋ค.
private๊ณผ fileprivate
fileprivate๋ ๊ฐ์ ํ์ผ ๋ด์ ์ด๋ค ์ฝ๋์์๋ ์ ๊ทผ ๊ฐ๋ฅํ๋ค. ๋ฐ๋ฉด, private๋ ๊ฐ์ ํ์ผ์ด์ด๋ ๋ค๋ฅธ ํ์ ์ฝ๋๋ ์ ๊ทผ ๋ถ๊ฐํ๊ณ ์์ ์ ํ์ฅํ๋ extension์ด ๊ฐ์ ํ์ผ์ ์กด์ฌํ ๊ฒฝ์ฐ ์ ๊ทผ ๊ฐ๋ฅํจ.
extension์ ํตํด computed properties๋ฅผ ์ถ๊ฐํ ์ ์๋ค. ๋ค์ ๋งํ๋ฉด stored prope
- instance computed property์ type computed property(static)์ ์ถ๊ฐํ ์ ์๊ณ , stored property์๋ ์ถ๊ฐํ ์ ์๋ค.
extension Double {
var km: Double { return self * 1_000.0 }
}โ read-only ํ๋กํผํฐ์ด๊ธฐ ๋๋ฌธ์ getter๋ง ์์ฑํด์ฃผ๋ฉด์ get ํค์๋๋ฅผ ์๋ตํ๋ค.
instance method์ type method๋ฅผ ๋ชจ๋ ์ถ๊ฐํ ์ ์๋ค.
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
// usage
3.repetitions {
print("hello")
}ํด๋์ค์์, ์๋ก์ด convenience initializer๋ฅผ ํด๋์ค์ ์ถ๊ฐํ ์ ์๋ค. ํ์ง๋ง designated initializer๋ deinitializer๋ฅผ ์ถ๊ฐํ ์๋ ์๋ค.
value-type(structure, enumerationโฆ)์์, ์๋ ํ์ ์์ defaut ๋๋ memberwise initializer๋ฅผ ์ด์ฉํ๊ณ ์๋ค๋ฉด extension initializer์์ ๊ธฐ๋ณธ/๋ฉค๋ฒ์์ด์ฆ ์ด๋์ ๋ผ์ด์ ธ๋ฅผ ํธ์ถํ ์ ์๋ค. ์ฆ custom initializer๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ extension์์ ์ ์ํ initializer์์ ๊ธฐ๋ณธ/๋ฉค๋ฒ์์ด์ฆ ์ด๋์ ๋ผ์ด์ ธ๋ฅผ ํธ์ถํ ์ ์๋ค.
๐ก ๊ธฐ๋ณธ ์ด๋์ ๋ผ์ด์ ธ๋ ์ ์ฅ ํ๋กํผํฐ์ ๊ธฐ๋ณธ๊ฐ์ด ๋ชจ๋ ์ง์ ๋์ด ์๊ณ , ๋์์ ์ฌ์ฉ์ ์ ์ ์ด๋์ ๋ผ์ด์ ธ๊ฐ ์ ์๋์ด์์ง ์์ ์ํ์์ ์ ๊ณต๋๋ค. (ํด๋์ค์ ๊ตฌ์กฐ์ฒด ๋ชจ๋)
๊ตฌ์กฐ์ฒด๋ ์ฌ์ฉ์ ์ ์ ์ด๋์ ๋ผ์ด์ ๋ฅผ ๊ตฌํํ์ง ์์ผ๋ฉด ํ๋กํผํฐ์ ์ด๋ฆ์ผ๋ก ๋งค๊ฐ๋ณ์๋ฅผ ๊ฐ๋ memberwise initializer๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ค. (ํด๋์ค๋ ์์ ๊ณตํจ) initializer ํธ์ถ์ default value๋ฅผ ๊ฐ์ง๋ ํ๋กํผํฐ๋ ์๋ตํ ์ ์๋ค.
์ด๋์ ๋ผ์ด์ ์์ ๋ค๋ฅธ ์ด๋์ ๋ผ์ด์ ๋ฅผ ํธ์ถํ๋ ๊ฒ์ initializer delegation ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. value type์์ self.init์ custom initializer ๋ด์์๋ง ์ฌ์ฉํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ custom initializer๋ฅผ ์์ฑํ๋ฉด default/memberwise initializer๋ ๋์ด์ ์ด์ฉํ ์ ์๋ค.
ํด๋์ค์๋ designated/convenience initializer๋ผ๋ ๋ ํ์ ์ ์ด๋์ ๋ผ์ด์ ธ๊ฐ ์กด์ฌํ๋ค. designated initializer๋ primary initializer์ด๋ค. ํด๋น ํด๋์ค๊ฐ ๊ฐ์ง๋ ๋ชจ๋ ํ๋กํผํฐ๋ฅผ ์ด๊ธฐํํ๊ณ , superclass initializer๋ฅผ ํธ์ถํ๋ค.
convenience initializer๋ secondary initialzier์ด๋ค. ํญ์ ๋ค๋ฅธ initializer๋ฅผ ๋ด๋ถ์์ ํธ์ถํ๊ฒ ๋๊ณ ํธ์ถ์์ ๊ฒฐ๊ตญ์ ํ๋์ designated initializer๋ฅผ ํธ์ถํด์ผ ํ๋ค.
struct Comic {
var title: String
let author: String
}
Comic(title: "๋ํผ๋ฉ", author: "๋ํผ๋ฉ์๊ฐ") // ์ฌ์ฉ์ ์ ์ ์ด๋์
๋ผ์ด์ ธ๊ฐ ์๋ ๊ฒฝ์ฐ ํ๋กํผํฐ๋ค์ ๋ชจ๋ ๋งค๊ฐ๋ณ์๋ก ๊ฐ๋ memberwise initializer๊ฐ ์ ๊ณต๋จ.
struct ComicWithInitializer {
var title: String
let author: String
init(comicTitle: String, comicAuthor: String) {
title = comicTitle
author = comicAuthor
}
}
// Error: labels ์ธ์๊ฐ ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค -> custom initializer๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ memberwise initialzier๋ ์ด์ฉํ ์ ์์
// ComicWithInitializer(title: "๋ํผ๋ฉ", author: "๋ํผ๋ฉ ์๊ฐ")struct Comic {
var title: String
let author: String
}
Comic(title: "๋ํผ๋ฉ", author: "๋ํผ๋ฉ์๊ฐ") // ์ฌ์ฉ์ ์ ์ ์ด๋์
๋ผ์ด์ ธ๊ฐ ์๋ ๊ฒฝ์ฐ ํ๋กํผํฐ๋ค์ ๋ชจ๋ ๋งค๊ฐ๋ณ์๋ก ๊ฐ๋ memberwise initializer๊ฐ ์ ๊ณต๋จ.
struct ComicWithInitializer {
var title: String
let author: String
init(comicTitle: String, comicAuthor: String) {
title = comicTitle
author = comicAuthor
}
}
// Error: labels ์ธ์๊ฐ ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค -> custom initializer๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ memberwise initialzier๋ ์ด์ฉํ ์ ์์
// ComicWithInitializer(title: "๋ํผ๋ฉ", author: "๋ํผ๋ฉ ์๊ฐ")
extension Comic {
init(title: String) {
self.init(title: title, author: "์์ ๋ฏธ์")
}
}
Comic(title: "๊ฐ์ฃผ๊ฐ ๋๊ฒ ์ต๋๋ค")
extension ComicWithInitializer {
init(title: String) {
self.init(comicTitle: title, comicAuthor: "์์ ๋ฏธ์")
}
}๋ค๋ฅธ ๋ชจ๋์์ ์ ์๋ structure์ extension์ ํตํด Initializer ๋ฅผ ์ถ๊ฐํ๋ ๊ฒฝ์ฐ, ๊ธฐ์กด์ initializer๋ฅผ ํธ์ถํ ํ์ self ๋ฅผ ์ด์ฉํ ์ ์๋ค.
[] ๋ฅผ ํตํด ํ๋กํผํฐ์ ์ ๊ทผํ๋ ๊ฒ
์๋ฅผ ๋ค์ด, array[1] ๋๋ dictionary[โkeyโ]์ฒ๋ผ collection, list, sequence์์ ๋ฉค๋ฒ element์ ์ ๊ทผํ ๋ ์ด์ฉํ๋ค.
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
}
// intInstance.kind ๋ก ์ ๊ทผ ๊ฐ๋ฅํ๋ค.extension์ ํตํด protocol conformance๋ฅผ ์ถ๊ฐํ ์๋ ์๋ค. ์ด๋ฅผ ์ํด extension ์์์ ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๊ธฐ ์ํด ํ์ํ ํ๋กํผํฐ, ๋ฉ์๋, ์๋ธ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํด์ผํ๋ค. ์ถ๊ฐ ํ๋กํผํฐ/๋ฉ์๋/์๋ธ์คํฌ๋ฆฝํธ ์์ด ์ด๋ฏธ ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๊ณ ์๋ ๊ฒฝ์ฐ์๋ ์ค๊ดํธ๋ฅผ ์ด์๋ง์ ๋ซ์์ฃผ๋ฉด ๋๋ค.
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}- ๋จ, Extension์ ํตํด์๋ computed property๋ง ์ถ๊ฐํ ์ ์๊ธฐ ๋๋ฌธ์ stored property ๋์ computed property๋ฅผ ์ถ๊ฐํด์คฌ๋ค.
ํ์
์ด ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ ๋์๋ง ํ๋กํ ์ฝ์ conformํ๋๋ก ํ ์๋ ์๋ค. ์ ๋ค๋ฆญ์ ์ด์ฉํ where ์ ์ ์ด์ฉํ๋ค.
๐ generic where: associated type์ด ํน์ ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๊ฑฐ๋, ํน์ ํ์ ํ๋ผ๋ฏธํฐ๊ฐ associated type๊ณผ ์ผ์นํ๋์ง์ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ค.
where + ์กฐ๊ฑด๋ฌธ๋ฒ์ ๊ฐ์ง๋ค.
import Foundation
protocol Container {
associatedtype Item
var items: [Item] { get }
mutating func append(_ item: Item)
}
struct IntStack: Container {
var items: [Int] = []
mutating func append(_ item: Int) {
items.append(item)
}
}
struct StringStack: Container {
var items: [String] = []
mutating func append(_ item: String) {
items.append(item)
}
}
extension Container where Item == Int {
var count: Int {
items.count
}
}
var intStack = IntStack()
intStack.append(1)
print(intStack.count)
var stringStack = StringStack()
stringStack.append("a")
//print(stringStack.count)-
extension์ ํตํด ์ด๋ฅผ ๋ง์กฑํ๋ ํด๋์ค/structure์ ๋ฉ์๋๋, initializer, subscript, computed property๋ฅผ ์ ๊ณตํ ์ ์๋ค.
protocol RandomNumberGenerator { var number: Double { get } } extension RandomNumberGenerator { func randomBool() -> Bool { return number > 0.5 } } class ABC: RandomNumberGenerator { var number = 0.5 } let generator = ABC() print(generator.randomBool())
ABC ํด๋์ค๊ฐ RandomNumberGenerator๋ฅผ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์, extension์ ํตํด ์ ๊ณต๋ randomBool ํจ์๋ฅผ ์ด์ฉํ ์ ์๋ค. randomBool ํจ์๋ฅผ ABC์์ ๊ตฌํํ ์๋ ์๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ABC์ randomBool ํจ์๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ABC์ randomBool ํจ์๋ฅผ ์ด์ฉํ๊ณ , ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ์๋ RandomNumberGenerator์ ํจ์๋ฅผ ์ด์ฉํ๋ค.
protocol MyProtocol {
func myNumber() -> Int
}
extension MyProtocol {
func myNumber() -> Int {
return 1
}
}
class MyClass: MyProtocol {}
let myInstance = MyClass()
print(myInstance.myNumber())์ด๋ฏธ ํ๋กํ ์ฝ์ ์ ์๋ ํจ์๋ property๋ฅผ ์ ์ํ ์๋ ์๋ค.