๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿฅ– Bread Basics/Swift

Swift ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ - ์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ… (Automatic Reference Counting)

by BreadDev 2025. 4. 13.
728x90

์•ˆ๋…•ํ•˜์„ธ์š”! ์˜ค๋Š˜์€ Swift์˜ '์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ…(Automatic Reference Counting, ARC)'์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” ์•ฑ ์„ฑ๋Šฅ๊ณผ ์•ˆ์ •์„ฑ์— ์ง๊ฒฐ๋˜๋Š” ์ค‘์š”ํ•œ ์ฃผ์ œ์ธ๋ฐ์š”, Swift์˜ ARC๋ฅผ ์ดํ•ดํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์—†๋Š” ํšจ์œจ์ ์ธ ์•ฑ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ARC๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ…(ARC)์€ Swift์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ž๋™์œผ๋กœ ์ถ”์ ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ARC๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

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

์ค‘์š”: ARC๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ตฌ์กฐ์ฒด(struct)์™€ ์—ด๊ฑฐํ˜•(enum)์€ ๊ฐ’ ํƒ€์ž…์ด๋ฏ€๋กœ ์ฐธ์กฐ๋กœ ์ €์žฅ๋˜๊ฑฐ๋‚˜ ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ARC์˜ ์ž‘๋™ ์›๋ฆฌ

ํด๋ž˜์Šค์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ARC๋Š” ์ธ์Šคํ„ด์Šค ์ •๋ณด๋ฅผ ์ €์žฅํ•  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”๋ชจ๋ฆฌ์—๋Š”:

  • ์ธ์Šคํ„ด์Šค์˜ ํƒ€์ž… ์ •๋ณด
  • ์ธ์Šคํ„ด์Šค์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ €์žฅ ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค

์ธ์Šคํ„ด์Šค๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ARC๋Š” ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜์—ฌ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•˜์ง€ ์•Š๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

ARC๊ฐ€ ์‚ฌ์šฉ ์ค‘์ธ ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•œ๋‹ค๋ฉด? ํ•ด๋‹น ์ธ์Šคํ„ด์Šค์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ์— ๋” ์ด์ƒ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜๊ณ , ์ ‘๊ทผ์„ ์‹œ๋„ํ•˜๋ฉด ์•ฑ์ด ์ถฉ๋Œ(crash)ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!

์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ARC๋Š” ๋ช‡ ๊ฐœ์˜ ํ”„๋กœํผํ‹ฐ, ์ƒ์ˆ˜, ๋ณ€์ˆ˜๊ฐ€ ๊ฐ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ํ™œ์„ฑ ์ฐธ์กฐ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์กด์žฌํ•˜๋Š” ํ•œ ARC๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ARC ์‹ค์ œ ๋™์ž‘ ์˜ˆ์ œ

๋‹ค์Œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ARC๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name)์ด(๊ฐ€) ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค")
    }
    deinit {
        print("\(name)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค")
    }
}

// ์˜ต์…”๋„ Person ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋“ค ์ƒ์„ฑ
var reference1: Person?
var reference2: Person?
var reference3: Person?

// ์ƒˆ Person ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
reference1 = Person(name: "ํ™๊ธธ๋™")
// ์ถœ๋ ฅ: "ํ™๊ธธ๋™์ด(๊ฐ€) ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค"

// ๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์—๋„ ํ• ๋‹น (๊ฐ•ํ•œ ์ฐธ์กฐ ์ถ”๊ฐ€)
reference2 = reference1
reference3 = reference1

// ๋‘ ๊ฐœ์˜ ๋ณ€์ˆ˜์—์„œ ์ฐธ์กฐ ํ•ด์ œ
reference1 = nil
reference2 = nil

// ์—ฌ์ „ํžˆ ํ•˜๋‚˜์˜ ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ๋‚จ์•„์žˆ์Œ
// ์ธ์Šคํ„ด์Šค๋Š” ํ•ด์ œ๋˜์ง€ ์•Š์Œ

// ๋งˆ์ง€๋ง‰ ๊ฐ•ํ•œ ์ฐธ์กฐ ํ•ด์ œ
reference3 = nil
// ์ถœ๋ ฅ: "ํ™๊ธธ๋™์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค"

์ด ์˜ˆ์ œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด:

  1. Person ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด reference1์— ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
  2. ์ด ์ธ์Šคํ„ด์Šค๋ฅผ reference2์™€ reference3์— ํ• ๋‹นํ•˜๋ฉด ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ 3๊ฐœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  3. reference1๊ณผ reference2๋ฅผ nil๋กœ ์„ค์ •ํ•ด๋„ reference3๊ฐ€ ์—ฌ์ „ํžˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์–ด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  4. ๋งˆ์ง€๋ง‰์œผ๋กœ reference3๋งˆ์ € nil๋กœ ์„ค์ •ํ•˜๋ฉด ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†์–ด์ง€๊ณ  ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ๋ฌธ์ œ

ARC๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ, ํŠน๋ณ„ํ•œ ์ƒํ™ฉ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ **๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด(Strong Reference Cycle)**์ž…๋‹ˆ๋‹ค.

๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์€ ๋‘ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๊ฐ€ ์„œ๋กœ๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ, ๋‘ ์ธ์Šคํ„ด์Šค๋Š” ์„œ๋กœ๋ฅผ "๋ถ™์žก๊ณ " ์žˆ์–ด ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 0์ด ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์˜ˆ์ œ

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("์•„ํŒŒํŠธ \(unit)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค") }
}

// ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
var john: Person? = Person(name: "ํ™๊ธธ๋™")
var unit4A: Apartment? = Apartment(unit: "4A")

// ์„œ๋กœ ์ฐธ์กฐํ•˜๋„๋ก ์„ค์ • (๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์ƒ์„ฑ)
john!.apartment = unit4A
unit4A!.tenant = john

// ์™ธ๋ถ€ ์ฐธ์กฐ ์ œ๊ฑฐ ์‹œ๋„
john = nil
unit4A = nil

// ๋‘ ์ธ์Šคํ„ด์Šค ๋ชจ๋‘ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์Œ
// deinit ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š์Œ

์œ„ ์ฝ”๋“œ์—์„œ Person๊ณผ Apartment ์ธ์Šคํ„ด์Šค๋Š” ์„œ๋กœ๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•˜์—ฌ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ ์ฐธ์กฐ์ธ john๊ณผ unit4A๋ฅผ nil๋กœ ์„ค์ •ํ•ด๋„ ๋‘ ์ธ์Šคํ„ด์Šค๋Š” ์—ฌ์ „ํžˆ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์–ด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ํ•ด๊ฒฐํ•˜๊ธฐ

Swift๋Š” ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  1. ์•ฝํ•œ ์ฐธ์กฐ(Weak References)
  2. ๋ฏธ์†Œ์œ  ์ฐธ์กฐ(Unowned References)

1. ์•ฝํ•œ ์ฐธ์กฐ(Weak References)

์•ฝํ•œ ์ฐธ์กฐ๋Š” ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์œ ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, ARC๊ฐ€ ์ฐธ์กฐ๋œ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•ด์ œํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜๋ฉด ์•ฝํ•œ ์ฐธ์กฐ๋Š” ์ž๋™์œผ๋กœ nil์ด ๋ฉ๋‹ˆ๋‹ค.

์•ฝํ•œ ์ฐธ์กฐ๋Š” weak ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?  // ์•ฝํ•œ ์ฐธ์กฐ๋กœ ์„ ์–ธ
    deinit { print("์•„ํŒŒํŠธ \(unit)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค") }
}

var john: Person? = Person(name: "ํ™๊ธธ๋™")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
// ์ถœ๋ ฅ: "ํ™๊ธธ๋™์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค"

unit4A = nil
// ์ถœ๋ ฅ: "์•„ํŒŒํŠธ 4A์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค"

์•ฝํ•œ ์ฐธ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • ํ•ญ์ƒ ์˜ต์…”๋„ ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋กœ ์„ ์–ธ๋ฉ๋‹ˆ๋‹ค (์ฐธ์กฐ๊ฐ€ nil์ด ๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ)
  • ์ฐธ์กฐ ๋Œ€์ƒ์ด ๋จผ์ € ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค

2. ๋ฏธ์†Œ์œ  ์ฐธ์กฐ(Unowned References)

๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋„ ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์œ ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•ฝํ•œ ์ฐธ์กฐ์™€ ๋‹ฌ๋ฆฌ, ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋Š” ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•ญ์ƒ ์ž์‹ ๋ณด๋‹ค ์˜ค๋ž˜ ์กด์žฌํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋Š” unowned ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค:

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค") }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer  // ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋กœ ์„ ์–ธ
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("์นด๋“œ #\(number)๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค") }
}

var john: Customer? = Customer(name: "ํ™๊ธธ๋™")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

john = nil
// ์ถœ๋ ฅ: "ํ™๊ธธ๋™์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค"
// ์ถœ๋ ฅ: "์นด๋“œ #1234567890123456๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค"

๋ฏธ์†Œ์œ  ์ฐธ์กฐ์˜ ํŠน์ง•:

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

๋ฏธ์†Œ์œ  ์˜ต์…”๋„ ์ฐธ์กฐ

Swift 5๋ถ€ํ„ฐ๋Š” ์˜ต์…”๋„ ํƒ€์ž…์—๋„ unowned๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

class Department {
    var name: String
    var courses: [Course]
    init(name: String) {
        self.name = name
        self.courses = []
    }
}

class Course {
    var name: String
    unowned var department: Department
    unowned var nextCourse: Course?  // ๋ฏธ์†Œ์œ  ์˜ต์…”๋„ ์ฐธ์กฐ
    init(name: String, in department: Department) {
        self.name = name
        self.department = department
        self.nextCourse = nil
    }
}

๐Ÿ“Œ ํด๋กœ์ €์™€ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด

ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ๊ฐ„์—๋งŒ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ํด๋กœ์ €(Closure)์™€ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ์‚ฌ์ด์—์„œ๋„ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

ํด๋กœ์ €์˜ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์˜ˆ์ œ

class HTMLElement {
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "์•ˆ๋…•ํ•˜์„ธ์š”")
print(paragraph!.asHTML())
// ์ถœ๋ ฅ: "<p>์•ˆ๋…•ํ•˜์„ธ์š”</p>"

paragraph = nil
// deinit ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š์Œ - ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐœ์ƒ

์ด ์˜ˆ์ œ์—์„œ asHTML ํด๋กœ์ €๋Š” self๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์บก์ฒ˜ํ•˜๊ณ , HTMLElement ์ธ์Šคํ„ด์Šค๋Š” asHTML ํด๋กœ์ €๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์ด ํ˜•์„ฑ๋˜์–ด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ํด๋กœ์ €์˜ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ํ•ด๊ฒฐํ•˜๊ธฐ

ํด๋กœ์ €์˜ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Swift๋Š” **์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ(Capture List)**๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ๋Š” ํด๋กœ์ € ๋‚ด์—์„œ ์บก์ฒ˜ํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ฐธ์กฐ ํƒ€์ž…์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉ๋ฒ•

class HTMLElement {
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        [unowned self] in  // ์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉ
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name)์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "์•ˆ๋…•ํ•˜์„ธ์š”")
print(paragraph!.asHTML())
// ์ถœ๋ ฅ: "<p>์•ˆ๋…•ํ•˜์„ธ์š”</p>"

paragraph = nil
// ์ถœ๋ ฅ: "p์ด(๊ฐ€) ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค"

์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ๋Š” ํด๋กœ์ €์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก ์•ž์— ๋Œ€๊ด„ํ˜ธ([]) ๋‚ด์— ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์˜ˆ์ œ์—์„œ [unowned self]๋Š” "ํด๋กœ์ €์—์„œ self๋ฅผ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋กœ ์บก์ฒ˜ํ•˜๋ผ"๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ ์ •์˜ ๋ฐฉ๋ฒ•

// ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ์žˆ๋Š” ๊ฒฝ์šฐ
lazy var someClosure = {
    [unowned self, weak delegate = self.delegate]
    (index: Int, stringToProcess: String) -> String in
    // ํด๋กœ์ € ๋ณธ๋ฌธ
}

// ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ์—†๋Š” ๊ฒฝ์šฐ
lazy var someClosure = {
    [unowned self, weak delegate = self.delegate] in
    // ํด๋กœ์ € ๋ณธ๋ฌธ
}

๐Ÿ“Œ ์•ฝํ•œ ์ฐธ์กฐ์™€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ ์ค‘ ์„ ํƒํ•˜๊ธฐ

์•ฝํ•œ ์ฐธ์กฐ์™€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ ์ค‘ ์–ด๋–ค ๊ฒƒ์„ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ์š”?

  1. ์•ฝํ•œ ์ฐธ์กฐ(weak)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:
    • ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๋จผ์ € ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ
    • ์ฐธ์กฐ๊ฐ€ ๋‚˜์ค‘์— nil์ด ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ
    • ์˜ˆ: ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํŒจํ„ด, ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„์—์„œ ๋ถ€๋ชจ๊ฐ€ ์ž์‹์„ ์ฐธ์กฐํ•  ๋•Œ
  2. ๋ฏธ์†Œ์œ  ์ฐธ์กฐ(unowned)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:
    • ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ž์‹ ๊ณผ ๊ฐ™์€ ์ˆ˜๋ช…์„ ๊ฐ€์ง€๊ฑฐ๋‚˜ ๋” ์˜ค๋ž˜ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ
    • ์ฐธ์กฐ๊ฐ€ ์ ˆ๋Œ€ nil์ด ๋˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
    • ์˜ˆ: ์‹ ์šฉ์นด๋“œ์™€ ๊ณ ๊ฐ์˜ ๊ด€๊ณ„์ฒ˜๋Ÿผ ํ•œ ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด ์—†์ด๋Š” ์กด์žฌํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ

๐Ÿ“Œ ์ •๋ฆฌ

์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ…(ARC)์€ Swift์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์ž๋™ํ™”ํ•˜์—ฌ ๊ฐœ๋ฐœ์ž์˜ ๋ถ€๋‹ด์„ ์ค„์—ฌ์ฃผ๋Š” ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•ฝํ•œ ์ฐธ์กฐ์™€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ธฐ์–ต ํฌ์ธํŠธ:

  • ARC๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค (๊ตฌ์กฐ์ฒด์™€ ์—ด๊ฑฐํ˜•์€ ๊ฐ’ ํƒ€์ž…)
  • ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์˜ ์ฃผ์š” ์›์ธ์ž…๋‹ˆ๋‹ค
  • ์•ฝํ•œ ์ฐธ์กฐ(weak)๋Š” ์ฐธ์กฐ๊ฐ€ nil์ด ๋  ์ˆ˜ ์žˆ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค
  • ๋ฏธ์†Œ์œ  ์ฐธ์กฐ(unowned)๋Š” ์ฐธ์กฐ๊ฐ€ ํ•ญ์ƒ ์œ ํšจํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค
  • ํด๋กœ์ €์—์„œ๋Š” ์บก์ฒ˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค