λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ₯– Bread Basics/Swift

Swift 곡식 λ¬Έμ„œ 정리 - ν™•μž₯ (Extensions)

by BreadDev 2025. 4. 13.
728x90

μ•ˆλ…•ν•˜μ„Έμš”. μ˜€λŠ˜μ€ Swift의 'ν™•μž₯(Extensions)'에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€. ν™•μž₯을 μ‚¬μš©ν•˜λ©΄ κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ κΈ°λŠ₯을 μ‰½κ²Œ μΆ”κ°€ν•  수 μžˆμ–΄, μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±κ³Ό μœ μ—°μ„±μ„ 크게 ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ“Œ ν™•μž₯μ΄λž€?

ν™•μž₯(Extensions)은 기쑴의 클래슀, ꡬ쑰체, μ—΄κ±°ν˜•, ν”„λ‘œν† μ½œμ— μƒˆλ‘œμš΄ κΈ°λŠ₯을 μΆ”κ°€ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. 심지어 μ†ŒμŠ€ μ½”λ“œμ— μ ‘κ·Όν•  수 μ—†λŠ” νƒ€μž…λ„ ν™•μž₯ν•  수 μžˆλ‹€λŠ” 점이 큰 μž₯μ μž…λ‹ˆλ‹€. 이λ₯Ό 'μ†ŒκΈ‰ λͺ¨λΈλ§(retroactive modeling)'이라고 ν•©λ‹ˆλ‹€.

μ°Έκ³ : Swift의 ν™•μž₯은 Objective-C의 μΉ΄ν…Œκ³ λ¦¬μ™€ μœ μ‚¬ν•˜μ§€λ§Œ, Swift ν™•μž₯은 이름이 μ—†λ‹€λŠ” 차이가 μžˆμŠ΅λ‹ˆλ‹€.

πŸ“Œ ν™•μž₯으둜 ν•  수 μžˆλŠ” 것

Swiftμ—μ„œ ν™•μž₯을 톡해 λ‹€μŒκ³Ό 같은 κΈ°λŠ₯을 μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

  1. κ³„μ‚°λœ ν”„λ‘œνΌν‹° (μΈμŠ€ν„΄μŠ€ 및 νƒ€μž… ν”„λ‘œνΌν‹°)
  2. λ©”μ„œλ“œ (μΈμŠ€ν„΄μŠ€ 및 νƒ€μž… λ©”μ„œλ“œ)
  3. μƒˆλ‘œμš΄ μ΄ˆκΈ°ν™” ꡬ문
  4. μ„œλΈŒμŠ€ν¬λ¦½νŠΈ
  5. 쀑첩 νƒ€μž…
  6. ν”„λ‘œν† μ½œ μ€€μˆ˜

μ€‘μš”ν•œ μ œν•œ 사항: ν™•μž₯은 κΈ°μ‘΄ κΈ°λŠ₯을 μž¬μ •μ˜ν•  수 μ—†μœΌλ©°, μ €μž₯ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ κΈ°μ‘΄ ν”„λ‘œνΌν‹°μ— ν”„λ‘œνΌν‹° κ΄€μ°°μžλ₯Ό μΆ”κ°€ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

πŸ“Œ ν™•μž₯ ꡬ문

ν™•μž₯은 extension ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•©λ‹ˆλ‹€:

extension SomeType {
    // 여기에 SomeType에 μΆ”κ°€ν•  μƒˆ κΈ°λŠ₯을 μž‘μ„±ν•©λ‹ˆλ‹€
}

ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λ„λ‘ νƒ€μž…μ„ ν™•μž₯ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€:

extension SomeType: SomeProtocol, AnotherProtocol {
    // ν”„λ‘œν† μ½œ μš”κ΅¬μ‚¬ν•­ κ΅¬ν˜„
}

πŸ“Œ κ³„μ‚°λœ ν”„λ‘œνΌν‹° μΆ”κ°€ν•˜κΈ°

ν™•μž₯을 톡해 κΈ°μ‘΄ νƒ€μž…μ— κ³„μ‚°λœ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒ μ˜ˆμ œλŠ” Swift의 Double νƒ€μž…μ— 거리 λ‹¨μœ„ λ³€ν™˜ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€:

extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}

let oneInch = 25.4.mm
print("1μΈμΉ˜λŠ” \(oneInch) λ―Έν„°μž…λ‹ˆλ‹€")
// 좜λ ₯: "1μΈμΉ˜λŠ” 0.0254 λ―Έν„°μž…λ‹ˆλ‹€"

let threeFeet = 3.ft
print("3ν”ΌνŠΈλŠ” \(threeFeet) λ―Έν„°μž…λ‹ˆλ‹€")
// 좜λ ₯: "3ν”ΌνŠΈλŠ” 0.914399970739201 λ―Έν„°μž…λ‹ˆλ‹€"

μ΄λŸ¬ν•œ ν™•μž₯을 μ‚¬μš©ν•˜λ©΄ λ‹¨μœ„ λ³€ν™˜ 계산을 μ•„μ£Ό μ§κ΄€μ μœΌλ‘œ ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

let aMarathon = 42.km + 195.m
print("λ§ˆλΌν†€μ€ \(aMarathon) λ―Έν„°μž…λ‹ˆλ‹€")
// 좜λ ₯: "λ§ˆλΌν†€μ€ 42195.0 λ―Έν„°μž…λ‹ˆλ‹€"

πŸ“Œ μ΄ˆκΈ°ν™” ꡬ문 μΆ”κ°€ν•˜κΈ°

ν™•μž₯을 톡해 κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ μ΄ˆκΈ°ν™” ꡬ문을 μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ€‘μš”: 클래슀 ν™•μž₯μ—λŠ” 편의 μ΄ˆκΈ°ν™” ꡬ문만 μΆ”κ°€ν•  수 있으며, μ§€μ • μ΄ˆκΈ°ν™” κ΅¬λ¬Έμ΄λ‚˜ μ΄ˆκΈ°ν™” ν•΄μ œ ꡬ문은 μΆ”κ°€ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ Rect ꡬ쑰체에 쀑심점과 크기둜 μ΄ˆκΈ°ν™”ν•˜λŠ” μƒˆ μ΄ˆκΈ°ν™” ꡬ문을 μΆ”κ°€ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€:

struct Size {
    var width = 0.0, height = 0.0
}

struct Point {
    var x = 0.0, y = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
}

extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))
// centerRect의 원점은 (2.5, 2.5)이고 ν¬κΈ°λŠ” (3.0, 3.0)μž…λ‹ˆλ‹€

이 μ˜ˆμ œμ—μ„œ Rect κ΅¬μ‘°μ²΄λŠ” μ›λž˜ κΈ°λ³Έ μ΄ˆκΈ°ν™” ꡬ문과 멀버별 μ΄ˆκΈ°ν™” ꡬ문만 κ°€μ§€κ³  μžˆμ—ˆμ§€λ§Œ, ν™•μž₯을 톡해 쀑심점과 크기둜 μ΄ˆκΈ°ν™”ν•˜λŠ” μƒˆλ‘œμš΄ 방법을 μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.

πŸ“Œ λ©”μ„œλ“œ μΆ”κ°€ν•˜κΈ°

ν™•μž₯을 톡해 κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œμ™€ νƒ€μž… λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

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

3.repetitions {
    print("μ•ˆλ…•ν•˜μ„Έμš”!")
}
// 좜λ ₯:
// μ•ˆλ…•ν•˜μ„Έμš”!
// μ•ˆλ…•ν•˜μ„Έμš”!
// μ•ˆλ…•ν•˜μ„Έμš”!

이 ν™•μž₯을 톡해 μ •μˆ˜μ— repetitions(task:) λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μ—¬, νŠΉμ • μž‘μ—…μ„ ν•΄λ‹Ή 숫자만큼 반볡 μ‹€ν–‰ν•  수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ³€κ²½ λ©”μ„œλ“œ(Mutating Methods)

κ΅¬μ‘°μ²΄λ‚˜ μ—΄κ±°ν˜•μ€ selfλ₯Ό λ³€κ²½ν•˜λŠ” λ©”μ„œλ“œμ— mutating ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€:

extension Int {
    mutating func square() {
        self = self * self
    }
}

var someInt = 3
someInt.square()
// someIntλŠ” 이제 9μž…λ‹ˆλ‹€

이 ν™•μž₯은 μ •μˆ˜ 값을 μ œκ³±ν•˜μ—¬ 자기 μžμ‹ μ„ λ³€κ²½ν•˜λŠ” λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

πŸ“Œ μ„œλΈŒμŠ€ν¬λ¦½νŠΈ μΆ”κ°€ν•˜κΈ°

ν™•μž₯을 톡해 κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ μ„œλΈŒμŠ€ν¬λ¦½νŠΈλ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}

746381295[0]  // 5 λ°˜ν™˜
746381295[1]  // 9 λ°˜ν™˜
746381295[2]  // 2 λ°˜ν™˜
746381295[8]  // 7 λ°˜ν™˜

이 ν™•μž₯은 μ •μˆ˜μ˜ νŠΉμ • μžλ¦Ώμˆ˜μ— μ ‘κ·Όν•  수 μžˆλŠ” μ„œλΈŒμŠ€ν¬λ¦½νŠΈλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 숫자의 였λ₯Έμͺ½μ—μ„œλΆ€ν„° 0번 μΈλ±μŠ€λŠ” 일의 자리, 1번 μΈλ±μŠ€λŠ” μ‹­μ˜ 자리λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

πŸ“Œ 쀑첩 νƒ€μž… μΆ”κ°€ν•˜κΈ°

ν™•μž₯을 톡해 κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ 쀑첩 νƒ€μž…μ„ μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

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

func printIntegerKinds(_ numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .negative:
            print("- ", terminator: "")
        case .zero:
            print("0 ", terminator: "")
        case .positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}

printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// 좜λ ₯: "+ + - 0 - 0 + "

이 ν™•μž₯은 Int νƒ€μž…μ— 숫자의 λΆ€ν˜Έλ₯Ό λ‚˜νƒ€λ‚΄λŠ” Kind μ—΄κ±°ν˜•κ³Ό ν•΄λ‹Ή μ •μˆ˜μ˜ μ’…λ₯˜λ₯Ό λ°˜ν™˜ν•˜λŠ” kind 계산 ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

πŸ“Œ ν™•μž₯의 μ‹€μš©μ  ν™œμš© 사둀

ν™•μž₯은 λ‹€μŒκ³Ό 같은 μƒν™©μ—μ„œ 특히 μœ μš©ν•©λ‹ˆλ‹€:

  1. ν‘œμ€€ 라이브러리 νƒ€μž… ν™•μž₯: String, Array, Int 등에 ν”„λ‘œμ νŠΈμ— νŠΉν™”λœ κΈ°λŠ₯ μΆ”κ°€
  2. ν”„λ‘œν† μ½œ μ€€μˆ˜: κΈ°μ‘΄ νƒ€μž…μ΄ μƒˆ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λ„λ‘ λ§Œλ“€κΈ°
  3. μ½”λ“œ ꡬ성: 큰 νƒ€μž…μ˜ κΈ°λŠ₯을 논리적 그룹으둜 뢄리
  4. Swiftier API: Objective-C APIλ₯Ό Swift μŠ€νƒ€μΌλ‘œ κ°œμ„ 
  5. κΈ°λŠ₯ λͺ¨λ“ˆν™”: νŠΉμ • κΈ°λŠ₯만 ν•„μš”ν•œ κ²½μš°μ— μ„ νƒμ μœΌλ‘œ ν™•μž₯ κ°€λŠ₯

πŸ“Œ ν™•μž₯의 μž₯점

  1. μ½”λ“œ μž¬μ‚¬μš©μ„±: κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ κΈ°λŠ₯을 μ‰½κ²Œ μΆ”κ°€
  2. μ†ŒμŠ€ μ ‘κ·Ό 없이 ν™•μž₯ κ°€λŠ₯: ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ μ„œλ“œνŒŒν‹° ν”„λ ˆμž„μ›Œν¬μ˜ νƒ€μž…λ„ ν™•μž₯ κ°€λŠ₯
  3. μ½”λ“œ 뢄리와 ꡬ성: κ΄€λ ¨ κΈ°λŠ₯을 λ…Όλ¦¬μ μœΌλ‘œ λΆ„λ¦¬ν•˜μ—¬ 가독성 ν–₯상
  4. μœ μ§€λ³΄μˆ˜μ„±: 원본 νƒ€μž…μ„ μˆ˜μ •ν•˜μ§€ μ•Šκ³  μƒˆ κΈ°λŠ₯ μΆ”κ°€ κ°€λŠ₯
  5. ν”„λ‘œν† μ½œ μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ°: ν”„λ‘œν† μ½œ ν™•μž₯κ³Ό ν•¨κ»˜ κ°•λ ₯ν•œ 좔상화 제곡

πŸ“Œ ν™•μž₯ μ‚¬μš© μ‹œ μ£Όμ˜μ‚¬ν•­

  1. μ €μž₯ ν”„λ‘œνΌν‹° μΆ”κ°€ λΆˆκ°€: ν™•μž₯μœΌλ‘œλŠ” μ €μž₯ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•  수 μ—†μŠ΅λ‹ˆλ‹€
  2. κΈ°μ‘΄ κΈ°λŠ₯ μž¬μ •μ˜ λΆˆκ°€: 이미 μ‘΄μž¬ν•˜λŠ” κΈ°λŠ₯을 λ³€κ²½ν•  수 μ—†μŠ΅λ‹ˆλ‹€
  3. μ΄ˆκΈ°ν™” ꡬ문 μ œν•œ: ν΄λž˜μŠ€μ—λŠ” 편의 μ΄ˆκΈ°ν™” ꡬ문만 μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€
  4. ν”„λ‘œν† μ½œ ν™•μž₯ μ œν•œ: ν”„λ‘œν† μ½œ ν™•μž₯μ—μ„œ μ œκ³΅ν•˜λŠ” κ΅¬ν˜„μ€ 직접 μž¬μ •μ˜ν•  수 μ—†μŠ΅λ‹ˆλ‹€
  5. 넀이밍 좩돌 주의: λ‹€μ–‘ν•œ ν™•μž₯으둜 μΈν•œ 이름 좩돌 κ°€λŠ₯성에 μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€

πŸ“Œ 정리

Swift의 ν™•μž₯은 κΈ°μ‘΄ νƒ€μž…μ— μƒˆλ‘œμš΄ κΈ°λŠ₯을 μΆ”κ°€ν•˜λŠ” 방법을 μ œκ³΅ν•©λ‹ˆλ‹€. μ½”λ“œ μž¬μ‚¬μš©μ„±, λͺ¨λ“ˆν™”, 가독성을 λ†’μ΄λŠ” 데 κΈ°μ—¬ν•˜λ©°, ν”„λ‘œν† μ½œ μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ λ„κ΅¬λ‘œ μ‚¬μš©λ©λ‹ˆλ‹€.

ν™•μž₯을 톡해 Swift ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ μ™ΈλΆ€ ν”„λ ˆμž„μ›Œν¬μ˜ νƒ€μž…μ„ 우리의 ν•„μš”μ— 맞게 ν™•μž₯ν•¨μœΌλ‘œμ¨, 더 ν‘œν˜„λ ₯ 있고 직관적인 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.