๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ Today I Learned/Swift ๋ฌธ๋ฒ•

[Swift] ARC(Automatic Reference Counting)๋ž€?

by Joseph Seong 2024. 1. 4.

 

 

ARC(Automatic Reference Counting) ๋ž€?

  • Swift๋Š” ARC๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Heap ์˜์—ญ์˜ ๊ฐ์ฒด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.
  • ARC๋Š” Heap ์˜์—ญ์˜ ๊ฐ์ฒด์— ๋Œ€ํ•œ Strong Reference(๊ฐ•ํ•œ ์ฐธ์กฐ) count๋ฅผ ์ถ”์ ํ•˜๊ณ ,
  • ๊ฐ์ฒด๊ฐ€ ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ (์ฐธ์กฐ count๊ฐ€ ์—†์„ ๋•Œ) ํ•ด๋‹น ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ํ•ด์ œํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

 

Strong Reference (๊ฐ•ํ•œ ์ฐธ์กฐ)

  • Swift์—์„œ ๋ณ€์ˆ˜๋‚˜ ์ƒ์ˆ˜๋Š” Strong Reference(๊ฐ•ํ•œ ์ฐธ์กฐ)๋ฅผ ํ•œ๋‹ค.
  • ๊ฐ์ฒด์— ๋Œ€ํ•œ Strong Reference count๊ฐ€ ์ฆ๊ฐ€๋˜์–ด ์žˆ๋‹ค๋ฉด,
  • ํ•ด๋‹น ๊ฐ์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€๋œ๋‹ค.
class Person { 		// Person์ด๋ผ๋Š” ์ฐธ์กฐ ํƒ€์ž…์˜ ํด๋ž˜์Šค
    var name: String
    init(name: String) {
        self.name = name
    }
}

// person1์ด๋ผ๋Š” Personํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์คŒ
var person1: Person? = Person(name: "Alice") // ๊ฐ•ํ•œ ์ฐธ์กฐ
var person2 = person1 // ๋˜ ๋‹ค๋ฅธ ๊ฐ•ํ•œ ์ฐธ์กฐ

// person1์ด nil์ด ๋˜๋”๋ผ๋„ person2๊ฐ€ ์—ฌ์ „ํžˆ strong ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๊ฐ์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ์œ ์ง€๋จ
person1 = nil

 

 

Circular References (์ˆœํ™˜ ์ฐธ์กฐ)

  • ARC ์ž‘๋™ ๋ฐฉ์‹์˜ ํŠน์„ฑ์ƒ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•˜๋Š” ๊ฒฝ์šฐ, ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. (๋ฌธ์ œ์ )
  • ๋‘ ๊ฐ์ฒด ๋ชจ๋‘ ๋”์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋”๋ผ๋„ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•˜๋Š” ๊ฒฝ์šฐ, Strong Reference count๊ฐ€ ๊ฐ์†Œํ•˜์ง€ ์•Š์•„,
  • ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ๋ชปํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ˆ„์ˆ˜๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ์•ฝํ•œ ์ฐธ์กฐ(weak reference)์™€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ(unowned reference) ๊ฐ™์€ ๋‹ค๋ฅธ ์ฐธ์กฐ ์œ ํ˜•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
class Person {
    var name: String
    // Petํƒ€์ž…์˜ pet ํ”„๋กœํผํ‹ฐ 
    var pet: Pet? // Person์ด ์†Œ์œ ํ•˜๋Š” Pet

    init(name: String) {
        self.name = name
    }
}

class Pet {
    var species: String
    // Personํƒ€์ž…์˜ owner ํ”„๋กœํผํ‹ฐ 
    var owner: Person? // Pet์„ ์†Œ์œ ํ•˜๋Š” Person

    init(species: String) {
        self.species = species
    }
}

// ๋‘ ์ฐธ์กฐ ํƒ€์ž„์ด ์„œ๋กœ ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
// ์ด๋ ‡๊ฒŒ ๋‘ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋˜๋ฉด ์ˆœํ™˜์ฐธ์กฐ ๋ฐœ์ƒ
// ๋‘ ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•ด์ œ๋˜๋”๋ผ๋„ ์ˆœํ™˜์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋จ
// ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Œ.

var person: Person? = Person(name: "Alice") // Person ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ
var pet: Pet? = Pet(species: "Dog") // Pet ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ

person?.pet = pet // Person ํด๋ž˜์Šค์˜ pet์— Pet ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹น
pet?.owner = person // Pet ํด๋ž˜์Šค์˜ owner์— Person ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹น

 

 

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

  • ์•ฝํ•œ ์ฐธ์กฐ๋Š” Strong Reference(๊ฐ•ํ•œ ์ฐธ์กฐ)์™€๋Š” ๋‹ฌ๋ฆฌ ๊ฐ์ฒด์˜ ์ฐธ์กฐ count ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.
  • ๊ฐ์ฒด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ฉด์„œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
class Person {
    var name: String
    // Personํƒ€์ž…์„ ๊ฐ€์ง€๋Š” friendํ”„๋กœํผํ‹ฐ ์กด์žฌ
    // weak ํ‚ค์›Œ๋“œ๋ฅผ ๋ณ€์ˆ˜์„ ์–ธ ์•ž์— ๋ถ™์—ฌ ํ•ด๋‹น Personํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์•ฝํ•œ์ฐธ์กฐ๋กœ ์„ ์–ธ
    weak var friend: Person? // ์•ฝํ•œ ์ฐธ์กฐ
    init(name: String) {
        self.name = name
    }
}

// person1, 2 ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  
var person1: Person? = Person(name: "Alice")
var person2: Person? = Person(name: "Bob")
// friend ํ”„๋กœํผํ‹ฐ๋ฅผ ์„œ๋กœ์˜ ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐ
person1?.friend = person2
person2?.friend = person1

// person1์ด nil๋กœ ํ• ๋‹น๋˜์–ด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋จ, ๊ทธ์— ๋”ฐ๋ผ person1๊ณผ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ๊ฐ์ฒด์˜ ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ ๊ฐ์†Œ๋จ
person1 = nil

 

 

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

  • ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋Š” ์•ฝํ•œ ์ฐธ์กฐ์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, optional ๊ฐ’์ด ์•„๋‹ˆ๋ผ์„œ nil๋กœ ์„ค์ •๋  ์ˆ˜ ์—†๋‹ค.
  • ๋งŒ์ผ ์ฐธ์กฐํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ์ด๋ฏธ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋œ ์ƒํƒœ์—์„œ ์ ‘๊ทผํ•˜๋ ค ํ•˜๋ฉด runtime error๊ฐ€ ๋ฐœ์ƒ๋˜๋ฉฐ,
  • ์‚ฌ์šฉ ์‹œ์ ์— ๊ฐ์ฒด๊ฐ€ ์ด๋ฏธ ํ•ด์ œ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ํ™•์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
class Country {
    var name: String
    var capital: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capital = City(name: capitalName, country: self)
    }
}

class City {
    var name: String
    // City ๊ฐ์ฒด ์‚ฌ์šฉ์‹œ์ ์—์„œ Country๊ฐ€ ํ•ด์ œ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ™•์‹ ํ•  ๊ฒฝ์šฐ์— ์‚ฌ์šฉ
    unowned var country: Country // ๋ฏธ์†Œ์œ  ์ฐธ์กฐ(unowned ํ‚ค์›Œ๋“œ)
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}