Skip to content

Latest commit

ย 

History

History
300 lines (225 loc) ยท 10.1 KB

File metadata and controls

300 lines (225 loc) ยท 10.1 KB

extensions

Extensions ์€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” class, structure, enumeration, protocol์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

Swift Extension์œผ๋กœ ๊ฐ€๋Šฅํ•œ ๊ฒƒ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • computed instance/type property ์ถ”๊ฐ€
  • instance/type ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
  • ์ด๋‹ˆ์…œ๋ผ์ด์ ธ ์ถ”๊ฐ€
  • ์„ญ์Šคํฌ๋ฆฝํŠธ ์ถ”๊ฐ€
  • ์ƒˆ๋กœ์šด nested types ์ถ”๊ฐ€
  • ํŠน์ • ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋„๋ก ๊ธฐ๋Šฅ ์ถ”๊ฐ€

์ƒ์†๊ณผ ์ต์Šคํ…์…˜

์ต์Šคํ…์…˜์€ ํƒ€์ž…์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์žฌ์ •์˜ํ•  ์ˆ˜๋Š” ์—†๋‹ค. ์ƒ์†์€ ํด๋ž˜์Šค์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ต์Šคํ…์…˜์€ structure, class, protocol, generic ๋“ฑ์—์„œ ๊ฐ€๋Šฅํ•˜๋‹ค.

Syntax

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์ด ๊ฐ™์€ ํŒŒ์ผ์— ์กด์žฌํ•  ๊ฒฝ์šฐ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•จ.

Computed Properties

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 ํ‚ค์›Œ๋“œ๋ฅผ ์ƒ๋žตํ–ˆ๋‹ค.

Method

instance method์™€ type method๋ฅผ ๋ชจ๋‘ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}

// usage
3.repetitions {
	print("hello")
}

Initializers

ํด๋ž˜์Šค์—์„œ, ์ƒˆ๋กœ์šด 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 ๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Subscripts

[] ๋ฅผ ํ†ตํ•ด ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ

์˜ˆ๋ฅผ ๋“ค์–ด, 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 7

Nested Types

extension 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 ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.

Adding Protocol Conformance with an Extension

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๋ฅผ ์ถ”๊ฐ€ํ•ด์คฌ๋‹ค.

Conditinally Conforming to a protocol

ํƒ€์ž…์ด ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๋•Œ์—๋งŒ ํ”„๋กœํ† ์ฝœ์„ 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)

Protocol Extensions

  • 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๋ฅผ ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.