๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โŒจ๏ธ Language/swift

[Swift] ARC

by hyebin (Helia) 2023. 2. 7.
๋ฐ˜์‘ํ˜•

ARC (Automatic Reference Counting)

  • ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•ด ์ฃผ๋Š” ๋ฐฉ์‹
  • ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์— ๊ฐœ๋ฐœ์ž๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์— ์‹ ๊ฒฝ์„ ์“ธ ํ•„์š”๊ฐ€ ์—†์Œ
  • ARC๋Š” ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘
  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ์ค‘, ํž™ ์˜์—ญ๊ณผ ๊ด€๋ จ
    • ํž™ ์˜์—ญ์€ ์ฐธ์กฐ(Reference) ํ˜• ํƒ€์ž…์ธ ํด๋ž˜์Šค, ํด๋กœ์ € ๋“ฑ์ด ๋ณด๊ด€
    • ๊ฐ’(Value) ํƒ€์ž…์ธ ๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐํ˜• ๋“ฑ์€ ๋ฉ”๋ชจ ๋ฆฌ ๊ด€๋ฆฌ ๋Œ€์ƒ์ด ์•„๋‹˜
  • ํž™ ์˜์—ญ์˜ ์ฐธ์กฐํ˜• ์ž๋ฃŒ๋“ค์ด ํ”„๋กœ๊ทธ๋žจ ์ƒ์—์„œ ์–ผ๋งˆ๋‚˜ ์ฐธ์กฐ๋˜๋Š”์ง€ ์ˆซ์ž๋ฅผ ์„ธ์–ด์„œ, ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€ ์ž๋™์œผ๋กœ ํ• ๋‹น ๋ฐ ์ œ๊ฑฐํ•˜๋„๋ก ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ

ARC ๋™์ž‘

  • ARC๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์˜€์„ ๋•Œ, ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น
  • ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”์ด ์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ, ARC๋Š” ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œ
  • ARC๋Š” ์ž˜๋ชป๋œ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๋“ค์ด ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ˆซ์ž๋ฅผ ์นด์šดํŠธ
  • Swift์—์„œ๋Š” ๊ฐ ๊ฐ์ฒด๋งˆ๋‹ค ์ฐธ์กฐ ํšŸ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ์ด ๊ฐœ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•ด์ œ๋˜์–ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๊ฒฐ์ •
  • ์ฐธ์กฐ ํšŸ์ˆ˜๊ฐ€ 0์ด ๋˜๋Š” ์ˆœ๊ฐ„๊นŒ์ง€ ARC๋Š” ๊ฐ์ฒด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•˜์ง€ ์•Š์Œ

 

๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ (Strong Reference Cycle)

  • ๋‘ ๊ฐœ์˜ ์ฐธ์กฐํ˜• ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์„œ๋กœ ๊ฐ•ํ•œ ์ธ์Šคํ„ด์Šค๋กœ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์–ด์„œ, ์ฐธ์กฐ ๊ฐœ์ˆ˜๊ฐ€ 0๊ฐœ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ์ƒํ™ฉ์„ ์˜๋ฏธ
  • ์ด๋“ค ์ธ์Šคํ„ด์Šค๋Š” ์ž์‹ ์„ ์„ ์–ธํ•œ ๋ณ€์ˆ˜๊ฐ€ nil ์ด ๋˜์–ด๋„, ์„œ๋กœ์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋น  ์ ธ๋‚˜๊ฐ€์ง€ ๋ชปํ•˜๊ฒŒ ๋˜๊ณ , ์ด๋กœ ์ธํ•ด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜(Memory Cycle) ๋ฐœ์ƒ
  • ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Œ
    • ํ•˜๋‚˜๋Š” weak ์ฐธ์กฐ, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” unowned ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ
    • weak ์ฐธ์กฐ, unowned ์ฐธ์กฐ ๋ชจ๋‘ ARC์—์„œ ์ฐธ์กฐ ํšŸ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š๊ณ  ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ๊ฐ€๋Šฅ
class Person {
    let name: String
    var apartment: Apartment?
 
    init(name: String) {
        self.name = name
    }
 
    deinit {
        print("\(name) is being deinitialized")
    }
}

class Apartment {
    let unit: String
    var tenant: Person?
    
    init(unit: String) {
        self.unit = unit
    }
    
    deinit {
        print("Apartment \(unit) is being deinitialized")
    }
}

 

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

  • ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๋จผ์ € ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋  ๋•Œ ์‚ฌ์šฉ
  • ๊ฐ•ํ•œ ์ฐธ์กฐ์™€ ๋‹ค๋ฅด๊ฒŒ ์ฐธ์กฐ ํšŸ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š์Œ
  • ๋ณ€์ˆ˜์˜ ์„ ์–ธ ์•ž์— weak ํ‚ค์›Œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉฐ, nil ์ด ํ• ๋‹น๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ์˜ต์…”๋„ ํƒ€์ž…
  • ARC์—์„œ ์•ฝํ•œ ์ฐธ์กฐ์— nil์„ ํ• ๋‹นํ•˜๋ฉด ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๋Š” ์‹คํ–‰๋˜์ง€ ์•Š์Œ
class Person {
    let name: String
    var apartment: Apartment?
 
    init(name: String) {
        self.name = name
    }
 
    deinit {
        print("\(name) is being deinitialized")
    }
}

class Apartment {
    let unit: String
    weak var tenant: Person?
 
    init(unit: String) {
        self.unit = unit
    }
 
    deinit {
        print("Apartment \(unit) is being deinitialized")
    }
}

 

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

  • ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ™์€ ์‹œ์  ํ˜น์€ ๋” ๋’ค์— ํ•ด์ œ๋  ๋•Œ ์‚ฌ์šฉ
  • ํ•ด๋‹น ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•˜์—ฌ Reference Counting์„ ํ•˜์ง€ ๋ง๋ผ๊ณ  ์„ ์–ธํ•˜๋Š” ๊ฒƒ
  • ๋ณ€์ˆ˜์˜ ์„ ์–ธ ์•ž์— unowned ํ‚ค์›Œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉฐ, ์˜ต์…”๋„ ํƒ€์ž… ์ผ ์ˆ˜๋„ ์žˆ๊ณ , ์•„๋‹ ์ˆ˜๋„ ์žˆ์ง€๋งŒ nil ์ผ ๊ฒฝ์šฐ์— ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ํ™•๋ฅ ์ด ํผ
  • ์ฐธ์กฐํ•˜๋Š” ๋™์•ˆ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์œผ๋ฆฌ๋ผ๋Š” ํ™•์‹ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ
class Customer {
    let name: String
    var card: CreditCard?
 
    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
 
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
     }
     deinit {
         print("Card #\(number) is being deinitialized")
     }
}

 

ํด๋กœ์ €์—์„œ์˜ ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜

  • ํด๋ž˜์Šค์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์ฐธ์กฐ ํƒ€์ž…์ธ ํด๋กœ์ €์—์„œ๋„ ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜์ด ๋ฐœ์ƒ ๊ฐ€๋Šฅ
  • ํด๋กœ์ € ๋‚ด๋ถ€์—์„œ self๋ฅผ ์บก์ฒ˜(capture)ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, self๋ฅผ ์•ฝํ•œ ์ฐธ์กฐ ํ˜น์€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋กœ ์ง€์ •ํ•˜๋ฉด ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ
    • capture: ์ž์‹ ์ด ์ •์˜๋˜๋Š” ์‹œ์ ์— ์ฃผ๋ณ€ ํ™˜๊ฒฝ์œผ๋กœ๋ถ€ํ„ฐ ์—ฌ๋Ÿฌ ์ƒ์ˆ˜๋‚˜ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์žก์•„๋‚ด์–ด ์ €์žฅ
lazy var someClosure: () -> String = { [weak self] in
 // ..
}
๋ฐ˜์‘ํ˜•