[Swift๐Ÿฆฉ] #25 ARC โญ๏ธโญ๏ธโญ๏ธ

๋˜์ƒยท2022๋…„ 4์›” 26์ผ
0

iOS

๋ชฉ๋ก ๋ณด๊ธฐ
41/47
post-thumbnail
  • Automatic Reference Conting ์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ…
  • Swift ๊ฐ€ ์ž๋™์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ถ”์ ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ARC ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ, ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ฆฐ๋‹ค.
  • ํ•˜์ง€๋งŒ, ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ํ•ด๊ฒฐํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ๋‹ค.
  • ์ฐธ์กฐ ์นด์šดํŒ…์ด๊ธฐ ๋•Œ๋ฌธ์— class ์—๋งŒ ์ ์šฉ๋œ๋‹ค.

1. ARC ์˜ ์ž‘๋™ ์›๋ฆฌ

  1. ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ : ๋ฉ”๋ชจ๋ฆฌ์˜ ์ฒญํฌ์— ํ• ๋‹น (ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ธ์Šคํ„ด์Šค์™€ ๊ด€๋ จ๋œ ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ ๊ฐ’๊ณผ ์ธ์Šคํ„ด์Šค ํƒ€์ž…์— ๋Œ€ํ•œ ์ •๋ณด ๊ฐ€์ง)
  2. ์ธ์Šคํ„ด์Šค ์‚ฌ์šฉ~~~
  3. ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ : ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•ด์ œ
  • ์‚ฌ์šฉ์ค‘์ธ ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹น ํ•ด์ œํ•ด๋ฒ„๋ฆฌ๋ฉด..? crash ๋ฐœ์ƒ
  • ๊ทธ๋ž˜์„œ ARC ๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ์ƒ์ˆ˜, ๋ณ€์ˆ˜, ํ•จ์ˆ˜, ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”์ ํ•ด์„œ
  • ํ•˜๋‚˜๋ผ๋„ ํด๋ž˜์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
  • ํ”„๋กœํผํ‹ฐ, ์ƒ์ˆ˜, ๋ณ€์ˆ˜์— ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹นํ•  ๋•Œ๋งˆ๋‹ค ํ”„๋กœํผํ‹ฐ, ์ƒ์ˆ˜, ๋ณ€์ˆ˜๋Š” ์ธ์Šคํ„ด์Šค์— ๊ฐ•ํ•œ ์ฐธ์กฐ ๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋œ๋‹ค.

2. ARC ๋™์ž‘

Person ์ด๋ผ๋Š” class ์ฝ”๋“œ๋กœ ์„ค๋ช…ํ•œ๋‹ค.

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

Optional ์„ ๋งŒ๋“ค๋ฉด nil ์ด ํ• ๋‹น๋˜์–ด, ์•„์ง ์ฐธ์กฐํ•˜๊ณ  ์žˆ์ง€ ์•Š์€ ์ƒํƒœ.

var reference1: Person?
var reference2: Person?
var reference3: Person?

์‹ค์ œ Person ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ํ• ๋‹นํ•˜๋Š” ์ˆœ๊ฐ„ ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.

reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"

// ๊ทธ๋Ÿฌ๋ฉด ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜์ง€ ์•Š๊ณ , ์ดˆ๊ธฐํ™” ๊ตฌ๋ฌธ๋งŒ ํ˜ธ์ถœํ•ด๋ฒ„๋ฆฌ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?
Person(name: "DDOSANG")
// ๊ฐ•ํ•œ ์ฐธ์กฐ 2๊ฐœ ์ถ”๊ฐ€. = 3
reference2 = reference1
reference3 = reference1


reference1 = nil // Person ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ 2
reference2 = nil // Person ์ธ์Šคํ„ด์Šค ๊ฐ•ํ•œ ์ฐธ์กฐ 1


reference3 = nil  // ๊ฐ•ํ•œ ์ฐธ์กฐ 0 : ์ด์ œ Person ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ. -> ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•ด์ œ 
// Prints "John Appleseed is being deinitialized"

3. ํด๋ž˜์Šค - ์ธ์Šคํ„ด์Šค ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด

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

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}
  • ์ดˆ๊ธฐ ์„ ์–ธ๊ณผ ํ• ๋‹น
// ์•„์ง ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š์Œ.
var john: Person?
var unit4A: Apartment?

// ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ”๊ณ  Person, Apartment ์ธ์Šคํ„ด์Šค์— ๊ฐ๊ฐ ์ฐธ์กฐ๊ฐ€ ์ƒ๊น€.
// ํ˜„์žฌ ๊ฐ ์ธ์Šคํ„ด์Šค ๋‚ด์˜ apartment, tenant ๋ณ€์ˆ˜๋Š” nil ๋กœ ํ• ๋‹น๋˜์–ด ์ฐธ์กฐ๋˜์ง€ ์•Š์€ ์ƒํƒœ.
john = Person(name: "John Appleseed") // Person ์ฐธ์กฐ 1
unit4A = Apartment(unit: "4A") // Apartment ์ฐธ์กฐ 1


๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์„œ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด??

john!.apartment = unit4A // Apartment ์ฐธ์กฐ 2
unit4A!.tenant = joh // Person ์ฐธ์กฐ 2


nil ๋กœ ๋ณ€๊ฒฝํ•ด๋„ ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 1์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋”์ด์ƒ ์“ฐ์ด์ง€ ์•Š๋Š”๋ฐ๋„ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ€์ง€ ์•Š๋Š” ์ƒํ™ฉ์ด ์˜จ๋‹ค.

john = nil // Person ์ฐธ์กฐ 1
unit4A = nil // Apartment ์ฐธ์กฐ 1


4. ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ํ•ด๊ฒฐ : weak self, unowned self โญ๏ธโญ๏ธ

  • ์ฐธ์กฐ ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜๋Š” ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ
  • ๊ฐ•ํ•œ ์ฐธ์กฐ ์œ ์ง€ ์—†์ด ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ํ•˜์—ฌ
  • ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์—†์ด ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

์•ฝํ•œ ์ฐธ์กฐ weak

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

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    // weak var ๋กœ ์„ ์–ธ.
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

์•„ํŒŒํŠธ ์ธ์Šคํ„ด์Šค ์ชฝ์—์„œ ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ํ•˜๊ณ  ์žˆ๋‹ค.

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

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

๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” Person ์„ ๋Š์–ด๋ฒ„๋ฆฌ๋ฉด?
์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” Apartment ์˜ tennant ๋Š” ์ž๋™์œผ๋กœ nil ์ด ํ• ๋‹น๋˜๋ฉฐ ์ฐธ์กฐ๊ฐ€ ๋Š์–ด์ง€๊ฒŒ ๋œ๋‹ค.

john = nil
// Prints "John Appleseed is being deinitialized"

๊ทธ๋ฆฌ๊ณ  unit4A ์ฐธ์กฐ๋„ ๋Š์œผ๋ฉด?

unit4A = nil
// Prints "Apartment 4A is being deinitialized"

๋‘˜ ๋‹ค ํ• ๋‹น์ด ํ•ด์ œ๋œ๋‹ค.

NOTE: ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์Šคํ…œ (ex. js) ์—์„œ๋Š” ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ์ด ๊ฐ€๋น„์ง€ ์ฝœ๋ ‰์…˜์„ ํŠธ๋ฆฌ๊ฑฐ ํ•  ๋•Œ๋งŒ ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์—†๋Š” ๊ฐ์ฒด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ์บ์‹ฑ์„ weak reference ๋กœ ํ™œ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ,

Swift ๋Š” ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 0์ด ๋˜์ž๋งˆ์ž ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ์บ์‹ฑ์„ ๊ทธ๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค๊ฐ„ ์บ์‹ฑ๋œ ๋ฐ์ดํ„ฐ๋Š” ์“ฐ์ง€ ๋ชปํ–ˆ๋Š”๋ฐ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


๋ฏธ์†Œ์œ  ์ฐธ์กฐ unowned

  • ์—ญ์‹œ ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์˜ ์ˆ˜๋ช…์ด ๊ฐ™๊ฑฐ๋‚˜ ๋” ๊ธด ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.
  • ํ•ญ์ƒ ๊ฐ’์„ ๊ฐ€์งˆ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋œ๋‹ค.
    • ๋‹น์—ฐํ•จ. weak ์—์„œ๋Š” ๋จผ์ € ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ„ ๊ฒฝ์šฐ nil ์ด ํ• ๋‹น๋์ง€๋งŒ,
    • unowned ๋Š” ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๋จผ์ € ๋‚ด๋ ค๊ฐ€์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฐ•ํ•œ ํ™•์‹ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉ
    • ๊ทธ๋ž˜์„œ Optional ๋กœ ์„ ์–ธ๋˜์–ด๋„ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ„๋‹ค๊ณ  nil ์ด ํ• ๋‹น๋˜์ง€ ์•Š๋Š”๋‹ค. -> let ๊ฐ€๋Šฅ.
    • ํ• ๋‹น ํ•ด์ œ๋œ ํ›„์— unowned ๊ฐ’์— ์ ‘๊ทผํ•˜๋ฉด runtime error ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • ์˜ˆ์ œ -> Customer / CreditCard
  • CreditCard ๋Š” Customer ๋ณด๋‹ค ์˜ค๋ž˜ ์ง€์†๋˜์ง€ ์•Š๋Š”๋‹ค.
    • CreditCard ๋Š” Customer ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ๋™์•ˆ ์“ฐ์ธ๋‹ค๊ณ  ํ™•์‹ .
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
    // customer ๋ฅผ unowned ๋ณ€์ˆ˜๋กœ ์„ค์ •.
    // weak ๊ณผ ๋‹ฌ๋ฆฌ ์ž๋™์œผ๋กœ nil ์ด ํ• ๋‹น๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ let ๊ฐ€๋Šฅ.
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\(number) is being deinitialized") }
}

var john: Customer? // nil

john = Customer(name: "John Appleseed") // Customer ARC 1
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!) // CreditCard ARC 1

๋งŒ์•ฝ john ์„ ๋Š๋Š”๋‹ค๋ฉด
CreditCard ARC 1
Customer ARC 0

์ด ๋˜์–ด์„œ, Customer ๊ฐ€ ๋‚ด๋ ค๊ฐ€๊ณ , CreditCard ๋„ ๋‚ด๋ ค๊ฐ„๋‹ค. CreditCard ๋„ ๊ฐ™์ด ๋‚ด๋ ค๊ฐ€๋Š” ๊ฒƒ. ๋‚จ์•„์„œ ์“ฐ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— unowned ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"

๋Œ€์‹  unowned ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ •๋ง๋กœ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ๊ฐ™์ด ํ˜น์€ ๋‚˜์ค‘์— ๋‚ด๋ ค๊ฐ€๋Š” ๊ฒƒ์ด ๋งž๋Š”์ง€์— ๋Œ€ํ•ด ์ •ํ™•ํ•˜๊ฒŒ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค.


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

  • ํด๋ž˜์Šค์—์„œ ์˜ต์…”๋„ ์ฐธ์กฐ๋ฅผ unowned ๋กœ ํ‘œ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฐจ์ด์ ์€, ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—
    • ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜
    • nil ์ด ์•„๋‹Œ์ง€ ํ™•์ธํ•ด์•ผ ํ•จ.
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? // ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด๋‹น ๋ณ€์ˆ˜๋“ค์ด ๋จผ์ € ๋‚ด๋ ค๊ฐ€ ๋ฒ„๋ฆฌ๋ฉด nil
    init(name: String, in department: Department) {
        self.name = name
        self.department = department
        self.nextCourse = nil
    }
}

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

๋ฐ”๋กœ ๊ฐ™์ด ๋‚ด๋ ค๊ฐ€๋‹ˆ๊นŒ unowned ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

let department = Department(name: "Horticulture")

let intro = Course(name: "Survey of Plants", in: department)
let intermediate = Course(name: "Growing Common Herbs", in: department)
let advanced = Course(name: "Caring for Tropical Plants", in: department)

intro.nextCourse = intermediate
intermediate.nextCourse = advanced
department.courses = [intro, intermediate, advanced]

NOTE : ์›๋ž˜ value type ์€ unowned ๋กœ ํ‘œ์‹œํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค. ๊ทธ๊ฒƒ์ด Swift ์˜ ๊ทœ์น™์ž„ (์ฐธ์กฐ๋Š” class ๋งŒ ํ•˜๋‹ˆ๊นŒ) ๊ทผ๋ฐ, Optinal ์€ enum ์ด์ง€๋งŒ unowned ๋กœ ํ‘œ๊ธฐํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์™ธ๊ฐ€ ์žˆ๋‹ค.

Optional("class instance") ๋Š” ์ฐธ์กฐ ์นด์šดํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.


Unowned References and Implicity Unwrapped Optional Properties

  1. weak - nil ์ด ๋  ์ˆ˜ ์žˆ๊ณ , ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ์œ ๋ฐœ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์„ ๋•Œ
  2. unowned - ํ•˜๋‚˜๋Š” nil ์ผ ์ˆ˜ ์žˆ๊ณ , ํ•˜๋‚˜๋Š” nil ์ผ ์ˆ˜ ์—†๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์„ ๋•Œ,
  3. ๋‘ ํ”„๋กœํผํ‹ฐ ๋ชจ๋‘ ํ•ญ์ƒ ๊ฐ’์ด ์žˆ๊ณ , ์ดˆ๊ธฐํ™”๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด nil ์ด๋ฉด ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ๋Š”..?
  • ํ•œ ํด๋ž˜์Šค์˜ unowned property ๋ฅผ ๋‹ค๋ฅธ ํด๋ž˜์Šค์— ์•”์‹œ์ ์œผ๋กœ ์–ธ๋ž˜ํ•‘ ๋œ Optional Property ์™€ ๊ฒฐํ•ฉํ•œ๋‹ค.
  • ์ฐธ์กฐ ์‚ฌ์ดํด์„ ํ”ผํ•˜๋ฉด์„œ, Optional Unwrapping ์—†์ด ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Type! ์„ ์“ฐ๋ฉด ํ•ด๋‹น ๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐํ˜•, ํด๋ž˜์Šค๊ฐ€ ๊ฐ€์ง„ ๋ชจ๋“  ์ €์žฅ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๊ธฐ ์ „์— self ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์—ˆ๋˜ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ,
  • Type! ์„ ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•œ ํ”„๋กœํผํ‹ฐ๋งŒ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€๊ฐ€ ์ดˆ๊ธฐํ™” ๋˜๋ฉด self ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฉด์„œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด๊นŒ์ง€ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.
class Country {
    let name: String
    var capitalCity: City! // ๊ธฐ๋ณธ nil ์ด๊ธฐ ๋•Œ๋ฌธ์—, init์—์„œ name ๋งŒ ์ดˆ๊ธฐํ™”ํ•˜๋ฉด Country ์ธ์Šคํ„ด์Šค๊ฐ€ ์™„๋ฒฝํ•˜๊ฒŒ ์ดˆ๊ธฐํ™” ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•œ๋‹ค.
    
    
    init(name: String, capitalName: String) {
        self.name = name
        
        // ์‚ฌ์‹ค country ๊ฐ€ ์™„๋ฒฝ ์ดˆ๊ธฐํ™” ๋˜๊ธฐ ์ „์—๋Š”, self ์— ์ ‘๊ทผํ•  ์ˆ˜๊ฐ€ ์—†์Œ.
        // City! ๋ผ๋Š” ์•”์‹œ์  ์–ธ๋ž˜ํ•‘์„ ์‚ฌ์šฉํ•˜๋ฉด name ์ด ์„ค์ •๋˜์ž๋งˆ์ž self ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}


// ๋Š๋‚Œํ‘œ ์•ˆ์“ฐ๊ณ  capitalCity ์ ‘๊ทผ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
// Prints "Canada's capital city is called Ottawa"

5. ํด๋กœ์ €์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด โญ๏ธโญ๏ธ

  • ์œ„์—์„œ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๊ฐ€ ์„œ๋กœ ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•ด์„œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์ด ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ดค๋Š”๋ฐ,

  • ํด๋กœ์ € ์—ญ์‹œ ์ฐธ์กฐํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์—

  • ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์˜ ํ”„๋กœํผํ‹ฐ์— ํด๋กœ์ €๋ฅผ ํ• ๋‹นํ•˜๊ณ ,

  • ํ•ด๋‹น ํด๋กœ์ €์˜ ๋ฐ”๋””์—์„œ ์ธ์Šคํ„ด์Šค self ๋ฅผ ์บก์ณํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

class HTMLElement {

    let name: String
    let text: String?

    // ํด๋กœ์ € ๋ณ€์ˆ˜. self ์บก์ณ. lazy ๋ผ์„œ self ์— ์ ‘๊ทผ ๊ฐ€๋Šฅ.
    // text ๊ฐ€ ์žˆ์œผ๋ฉด <tag>text</tag>
    // ์—†์œผ๋ฉด <tag /> ๋กœ ๋ฐ˜ํ™˜.
    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) is being deinitialized")
    }

}

์ด๋Ÿฐ ์‹์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") // Optinal(HTMLElement)
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"

ํด๋กœ์ €์™€ paragraph ๊ฐ€ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์„œ๋กœ๋ฅผ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด์— ๋ชฐ์•„๋„ฃ๊ฒŒ ๋œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋กœ๋Š” ๋‹น์—ฐํžˆ ์‚ฌ์ดํด์ด ๋Š๊ธฐ์ง€ ์•Š์Œ.

paragraph = nil

6. ํด๋กœ์ €์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์‚ฌ์ดํด ํ•ด๊ฒฐ

  • ์—ญ์‹œ ์•ฝํ•œ ์ฐธ์กฐ๋‚˜ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค.

NOTE : ์• ์ดˆ์— ํด๋กœ์ € ์•ˆ์—์„œ๋Š” self.method(), self.property ์ฒ˜๋Ÿผ self ๋ฅผ ๋ช…์‹œํ•ด์•ผ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ๋ฐ, ์ˆœํ™˜ ์ฐธ์กฐ ๊ฐ€๋Šฅ์„ฑ์„ ์ƒ๊ฐํ•ด๋ณด๋ผ๋Š” ๋œป์ด๋‹ค.

์บก์ฒ˜ ๋ชฉ๋ก ์ •์˜

ํด๋กœ์ €๋Š”

  • self ๊ฐ™์€ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค
  • ์–ด๋–ค ํŠน์ •ํ•œ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ํ”„๋กœํผํ‹ฐ
  • ๋” ๋งŽ์€ ์บก์ฒ˜ ๋ชฉ๋ก์€ ์—ฌ๊ธฐ

๋ฅผ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ๊ณ , self, ํ”„๋กœํผํ‹ฐ ๊ฐ๊ฐ์— weak / unowned ์„ค์ •์„ ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

lazy var someClosure = {
    [unowned self, weak delegate = self.delegate]
    (index: Int, stringToProcess: String) -> String in
    // closure body goes here
}

// ์ปจํ…์ŠคํŠธ ์œ ์ถ” ์‚ฌ์šฉ.
lazy var someClosure = {
    [unowned self, weak delegate = self.delegate] in
    // closure body goes here
}

์•ฝํ•œ ์ฐธ์กฐ์™€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ

  • ํด๋กœ์ €์™€ ์บก์ณํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๋ฉด์„œ ๊ฐ™์€ ์‹œ๊ฐ„์— ํ• ๋‹น์ด ํ•ด์ œ๋œ๋‹ค๋ฉด, ๋ฏธ์†Œ์œ  ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ์น˜๋งŒ ๊ฐ™์€ ์‹œ๊ฐ„์— ํ• ๋‹น๋˜์ง€ ์•Š๊ณ , ์บก์ฒ˜๋œ self ์— ๋Œ€ํ•œ ์ฐธ์กฐ๊ฐ€ nil ์ด ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
class HTMLElement {

    let name: String
    let text: String?

    // HTMLElement ์ธ์Šคํ„ด์Šค๊ฐ€ ๋‚ด๋ ค๊ฐˆ ๋•Œ ์–˜๋„ ๋‚ด๋ ค๊ฐ€์•ผํ•˜๋‹ˆ๊นŒ unowned
    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) is being deinitialized")
    }

}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"



์งˆ๋ฌธ

ARC๋ž€ ๋ฌด์—‡์ธ์ง€ ์„ค๋ช…ํ•˜์‹œ์˜ค.

  • ARC ๋Š” Swift ์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์‹œ์Šคํ…œ์œผ๋กœ
  • ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ณ€์ˆ˜, ํ”„๋กœํผํ‹ฐ, ํด๋กœ์ €๊ฐ€ ์ƒ๊ธฐ๋ฉด ์ฐธ์กฐ ์นด์šดํŠธ๋ฅผ ์˜ฌ๋ฆฌ๊ณ 
  • nil ๋กœ ํ• ๋‹น ํ•ด์ œ๋˜๋ฉด ์ฐธ์กฐ ์นด์šดํŠธ๋ฅผ ๋‚ด๋ฆฌ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.
  • ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 0 ์ด ๋˜๋ฉด ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ์—์„œ๋„ ๋‚ด๋ฆฐ๋‹ค.

Retain Count ๋ฐฉ์‹์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜์‹œ์˜ค.

  • Reference Count ์™€ ๊ฐ™์Œ.
  • ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•˜๋Š” ํ”„๋กœํผํ‹ฐ, ํด๋กœ์ € ๋“ฑ์˜ ์ฐธ์กฐ ํƒ€์ž…์ด ์žˆ์œผ๋ฉด 1 ์ฆ๊ฐ€, ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ์—†์–ด์ง€๋ฉด 1 ๊ฐ์†Œ
  • count ๊ฐ€ 0์ด ๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ• ๋‹น์„ ํ•ด์ œํ•œ๋‹ค.

Strong ๊ณผ Weak ์ฐธ์กฐ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜์‹œ์˜ค.

  • Strong ์€ ๊ฐ•ํ•œ ์ฐธ์กฐ์ธ๋ฐ, Strong ์œผ๋กœ ์ฐธ์กฐ๋˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ€์ง€ ์•Š๊ณ  ๋‚จ๊ฒŒ ๋œ๋‹ค.
  • Weak ๋Š” ์•ฝํ•œ ์ฐธ์กฐ์ธ๋ฐ, Weak ์™ธ์— Strong ์œผ๋กœ ํ•ด๋‹น ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ํ•˜๋‚˜๋„ ์—†์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ„๋‹ค. weak ์˜ ๊ฒฝ์šฐ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ๋จผ์ € ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, nil ๊ฐ’์ด ํ• ๋‹น๋  ์ˆ˜ ์žˆ๋‹ค.

์ˆœํ™˜ ์ฐธ์กฐ์— ๋Œ€ํ•˜์—ฌ ์„ค๋ช…ํ•˜์‹œ์˜ค.

  • ๊ฐ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค(์ฐธ์กฐ ํƒ€์ž…)์ด ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด์„œ, A ์•ˆ์— B ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๊ณ , B ์•ˆ์— A ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ ,
  • A ์™€ B ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ๊ฐ ๋งŒ๋“ค์–ด์„œ ์„œ๋กœ์—๊ฒŒ ํ• ๋‹น์„ ํ•ด์ฃผ๋ฉด, ์„œ๋กœ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์„œ๋กœ๋ฅผ ๊ฐ€๋ฅดํ‚ค๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ˆœํ™˜ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๋งํ•œ๋‹ค.

๊ฐ•ํ•œ ์ˆœํ™˜ ์ฐธ์กฐ (Strong Reference Cycle) ๋Š” ์–ด๋–ค ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ•˜๋Š”์ง€ ์„ค๋ช…ํ•˜์‹œ์˜ค.

  • ๊ฐ•ํ•œ ์ˆœํ™˜ ์ฐธ์กฐ๋Š” ์ˆœํ™˜ ์ฐธ์กฐ ์ƒํƒœ์—์„œ ์„œ๋กœ๊ฐ€ ์„œ๋กœ๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ์ฐธ์กฐํ•˜๊ณ  ์žˆ์–ด์„œ ์‹ค์ œ๋กœ๋Š” ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์ง€ ์•Š์œผ๋‚˜ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋‚ด๋ ค๊ฐ€์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค.
  • weak, unowned ๋ผ๋Š” ํ‚ค์›Œ๋“œ๋กœ ํ•ด๊ฒฐ.
  • ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์„œ๋กœ ์ฐธ์กฐํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํ•ด๋‹น ๋ณ€์ˆ˜์— weak / unowned ๋ฅผ ๋ถ™์—ฌ์„œ ์„ ์–ธํ•œ๋‹ค.



์ฐธ๊ณ 
https://bbiguduk.gitbook.io/swift/language-guide-1/automatic-reference-counting

profile
0๋…„์ฐจ iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€