Focus On Develop ๐ŸคŸ๐ŸคŸ

[Swift] strong, weak, unowned ๋ณธ๋ฌธ

iOS [Swift]/๊ธฐ์ดˆ๋ฅผ ํƒ„ํƒ„ํžˆ!

[Swift] strong, weak, unowned

๋ˆ„๋ฆฌ๋‹ฌ์ดํ‹€ 2021. 1. 29. 23:39

๋จผ์ € ARC์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ ์งš๊ณ  ๋„˜์–ด์™€์•ผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ๐Ÿ‘

๐Ÿ‘‰ 2021/01/29 - [iOS [Swift]] - [Swift] ARC (Automatic Reference Counting)

 

์ž ๊น ์š”์•ฝํ•˜๋ฉด

ARC๋Š” Swift์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ด์ค€๋‹ค๋Š” ๊ฐœ๋…์ธ๋ฐ, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ํ•ด์ฃผ์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํฌ์ธํŠธ๊ฐ€ ์žˆ์—ˆ์ฃ . ๊ทธ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํฌ์ธํŠธ๋Š” ์–ธ์ œ์ด๋ฉฐ, ์–ด๋–ป๊ฒŒ ๋ฐฉ์ง€๋ฅผ ํ•ด์•ผ ํ• ์ง€์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค.


** ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” Swift ๊ณต์‹ Document๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค **

[Swift Docs] docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

 

Automatic Reference Counting — The Swift Programming Language (Swift 5.3)

Automatic Reference Counting Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yours

docs.swift.org

 

ARC ์ •๋ฆฌ๋ฅผ ํ•˜๋ฉด์„œ Object๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋Š” ๊ฑด ์ด์ œ ์•Œ๊ฒ ๋Š”๋ฐ, ์ฐธ์กฐ์˜ ๋ฐฉ๋ฒ•๋„ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ์–ด์š”.

string (๊ฐ•ํ•œ) / weak(์•ฝํ•œ) / unowned(๋ฏธ์†Œ์œ ) 3๊ฐ€์ง€ Reference Cycles (์ฐธ์กฐ ์ˆœํ™˜) ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

 

๋จผ์ € string reference cycle(๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜)์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}
 
class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

์œ„์™€ ๊ฐ™์ด Person , Apartment ํด๋ž˜์Šค๊ฐ€ ์žˆ์„๋•Œ

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

๊ฐ๊ฐ Object๋ฅผ ๋งŒ๋“ค์–ด john, number73 ์ด๋ผ๋Š” ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ด์š”. ( = john, number73 ๊ฐ€ ์ƒˆ๋กœ ๋งŒ๋“  Object๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋Š” ์˜๋ฏธ)

์ด๋•Œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณ€์ˆ˜๊ฐ€ Object๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ์‹์ด strong ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค. john๊ณผ number73์€ ๊ฐ๊ฐ Object์— ๋Œ€ํ•ด ๊ฐ•ํ•œ์ฐธ์กฐ๋ฅผ ๊ฐ€์ ธ์š”.

john์˜ apartment์™€ number73์˜ tenant๊ฐ€ ๊ฐ๊ฐ nil์ด์—ฌ์„œ, ์ง€๊ธˆ ์ƒํƒœ๋กœ๋Š” john๊ณผ number73์€ ์ „ํ˜€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

john = nil
number73 = nil

์ด๋ ‡๊ฒŒ nil์„ ๊ฐ๊ฐ ํ• ๋‹นํ•ด์ฃผ๋ฉด, deinit์ด ํ˜ธ์ถœ๋˜์–ด ๋ฉ”๋ชจ๋ฆฌ ์ƒ์—์„œ Reference Count(์ฐธ์กฐ๊ณ„์ˆ˜)๊ฐ€ 0์ด๋˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ง€์›Œ์ ธ์š”.

 

๊ทธ๋Ÿฐ๋ฐ ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ์–ด๋–จ๊นŒ์š”?

john!.apartment = number73
number73!.tenant = john

๊ทธ๋ ‡๋‹ค.. ์ด์ œ๋Š” john์˜ apartment์™€ Apartment์˜ tenant๋ฅผ ํ• ๋‹นํ•ด์คŒ์œผ๋กœ์จ, ์•„๋ž˜์™€ ๊ฐ™์ด ์„œ๋กœ ๊ฐ•ํ•œ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜์š”.

์ด๋Ÿฐ ์ƒํƒœ์—์„œ ๋‹ค์‹œ john๊ณผ number73์„ nil๋กœ ํ• ๋‹นํ•˜๋ฉด

john = nil
number73 = nil

๋” ์ด์ƒ john๊ณผ number73๋Š” Object๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š์•„์š”. ๋‹ค๋งŒ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด, Object๋ผ๋ฆฌ ์„œ๋กœ ๊ฐ•ํ•œ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ Reference Count(์ฐธ์กฐ๊ณ„์ˆ˜)๋ฅผ Object ๊ฐ๊ฐ 1์”ฉ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒŒ ๋˜์ฃ ? ๊ทธ์— ๋”ฐ๋ผ Garbage Collector๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ด ๋‘๊ฐœ์˜ Object๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ„์ฃผํ•˜๊ณ  ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ง€์šฐ์ง€ ์•Š๊ณ  ๋‚จ๊ฒจ๋‘ก๋‹ˆ๋‹ค..๐Ÿ˜‚

๋ฐ”๋กœ ์ด ํฌ์ธํŠธ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒ๋˜๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค..!!!

์ด์ œ ์ € Object ๋‘๊ฐœ๋Š” ์˜์˜ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ฌ๋ผ์ง€์ง€ ์•Š์„๊บผ์•ผ.. ๐Ÿ˜ญ๐Ÿ˜ญ

 

์ด๋Ÿฐ ๊ฐ•๋ ฅ ์ฐธ์กฐ ์ˆœํ™˜์„ ์‚ฌ์šฉํ• ๋•Œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋‚ญ๋น„๋˜๋Š” ํฌ์ธํŠธ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ์•ˆ์œผ๋กœ 2๊ฐ€์ง€๊ฐ€ ์žˆ์–ด์š”.

๋ฐ”๋กœ.. ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ "์•ฝํ•œ ์ฐธ์กฐ ์ˆœํ™˜"๊ณผ "๋ฏธ์†Œ์œ  ์ฐธ์กฐ ์ˆœํ™˜" ์ด์—์š”.

 

๋จผ์ € weak Reference Cycle(์•ฝํ•œ ์ฐธ์กฐ ์ˆœํ™˜)์€ Object ๋ผ๋ฆฌ ์ฐธ์กฐํ• ๋•Œ ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ํ•˜๋„๋ก ํ•ด์„œ, Reference Count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ๋ฉ๊ทธ๋Ÿฌ๋‹ˆ ๋‚จ์•„์žˆ๋Š” Object๋ฅผ ์ฐธ์กฐํ•  ๋•Œ, ๋” ์ด์ƒ ์ฐธ์กฐํ•˜์ง€ ์•Š๋„๋ก ์ฐธ์กฐ๋ฅผ ๊นจ๋ฒ„๋ฆฌ๊ฒŒ ๋˜๋Š”๊ฑฐ์ฃ !

์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ weakํ‚ค์›Œ๋“œ๋ฅผ ์•ž์— ์‚ฌ์šฉํ•ด์ค๋‹ˆ๋‹ค. weak์œผ๋กœ ์„ ์–ธํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ nil์ผ ์ˆ˜ ์žˆ์–ด์„œ, ๋ฐ˜๋“œ์‹œ Optional๋กœ ์„ ์–ธ๋˜์–ด nil์ด ํ• ๋‹น๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”. ๋ฌผ๋ก  ์‹ค์ œ๋กœ weak์„ ์‚ฌ์šฉํ• ๋•Œ๋Š” unwrapping์„ ์ž˜ ๊ฑฐ์ณ์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค!

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}
 
class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    weak var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

๊ฐ•ํ•œ ์ฐธ์กฐ์™€ ๋™์ผํ•˜์ง€๋งŒ, ํ•œ๊ฐ€์ง€ ๋‹ฌ๋ผ์ง„ ์ ์€ tanant๊ฐ€ weak์œผ๋กœ ์„ ์–ธ๋˜์—ˆ๋‹ค๋Š” ์ ์ด์—์š”.

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

john!.apartment = number73
number73!.tenant = john

์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์„ ๋™์ผํ•˜๊ฒŒ ์ƒ๊ฐํ•ด๋ณด๋ฉด, john๊ณผ number73์€ ์„œ๋กœ์˜ Object๊ฐ€ ์ฐธ์กฐ๋ฅผ ํ•˜๊ฒŒ ๋˜์ฃ ?

ํ•˜์ง€๋งŒ ์ด๋ฒˆ์—๋Š” weak๋กœ ์„ ์–ธํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Object๊ฐ„ ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜๋Š”๋ฐ,

john = nil

john์„ nil๋กœ ํ• ๋‹นํ•ด john์ด ๊ฐ€์ง€๋Š” ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ๊นจ๋ฉด, Person Object์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค!

์ด์ œ Apartment์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ์ฐธ์กฐ๋Š” number73์— ๋Œ€ํ•œ ๊ฒƒ๋งŒ ๋‚จ์•„์žˆ๊ณ , ์ด๋งˆ์ €๋„ ๊นจ๋ฒ„๋ฆฌ๋ฉด ๋” ์ด์ƒ ๊ฐ•๋ ฅ ์ฐธ์กฐ๋Š” ๋‚จ์•„์žˆ์ง€ ์•Š๊ฒŒ ๋˜๋Š”๊ฑฐ์—์š”.

number73 = nil

์œ„์—์„œ ๊ฐ•ํ•œ์ฐธ์กฐ ์ผ๋•Œ๋Š” Object ์„œ๋กœ๊ฐ„ ์ฐธ์กฐ๋ฅผ ํ•˜๊ณ  ์žˆ์–ด์„œ Garbage Collector๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ด Object๋“ค์„ ์ง€์›Œ๋ฒ„๋ฆฌ์ง€ ์•Š์•˜๋Š”๋ฐ, ์•ฝํ•œ ์ฐธ์กฐ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋“ฏ์ด ์˜๋ฏธ์—†๋Š” Object๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์„ ๊นจ๋ฒ„๋ฆฌ๊ณ  Reference Count๊ฐ€ 0์ด ๋˜์–ด ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ๋˜๊ณ , ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!

 

๋งˆ์ง€๋ง‰์œผ๋กœ unowned Reference Cycle(๋ฏธ์†Œ์œ  ์ฐธ์กฐ ์ˆœํ™˜)์€ ์•ฝํ•œ ์ฐธ์กฐ์™€ ๋น„์Šทํ•˜๊ฒŒ Obejct์— ๋Œ€ํ•ด ์•ฝํ•œ์ฐธ์กฐ๋ฅผ ๊ฐ€์ ธ์š”. ๋‹ค๋งŒ Concept์ด ๋‹ค๋ฅธ๊ฒŒ ์žˆ๋‹ค๋ฉด weak์€ nil์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ญ์ƒ Optional๋กœ ์ •์˜ํ•˜๋Š”๋ฐ, unowned๋Š” ๋ฐ˜๋“œ์‹œ ์–ด๋–ค ๊ฐ’์„ ๊ฐ€์ ธ์•ผํ•œ๋‹ค๋Š” ๊ฑฐ์—์š”! ์ฆ‰ Optional๋กœ ์ •์˜ํ•  ์ˆ˜ ์—†์–ด์š”. unowned์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„ ์–ธ์‹œ ์•ž์— unowned ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { println("\(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 { println("Card #\(number) is being deinitialized") }
}

์ด๋ ‡๊ฒŒ Customer, CreditCard ํด๋ž˜์Šค๊ฐ€ ์žˆ์„๋•Œ, CreditCard๊ฐ€ ๋ฏธ์†Œ์œ  ์ฐธ์กฐ ํ•˜๋„๋ก ์„ ์–ธํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฐธ์กฐ ๊ตฌ์„ฑ์„ ๊ฐ€์ง€๊ฒŒ ๋˜๊ฒ ์ฃ ?

var john: Customer?

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

 

์—ฌ๊ธฐ์„œ john์˜ ๊ฐ•๋ ฅ ์ฐธ์กฐ๋ฅผ ๊นจ๋ฉด

john = nil

์ด๋ ‡๊ฒŒ ์•ฝํ•œ ์ฐธ์กฐ๋งŒ ๋‚จ์•„์„œ, Object ๋ผ๋ฆฌ์˜ ์ฐธ์กฐ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊นจ์ง€๊ณ  Garbage Collector์— ์˜ํ•ด ๋ฉ”๋ชจ๋ฆฌ์ƒ์—์„œ ์ง€์›Œ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!

 

์‚ฌ์‹ค unowned๋Š”.. ์ ˆ๋Œ€ nil์ด ์•„๋‹Œ Object..!? ๋ผ๋Š” ์ƒํ™ฉ์€ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ๋งŽ์€ ์œ„ํ—˜์ด ๋”ฐ๋ฅด๋Š” ๋ฐฉ๋ฒ•์ด์—์š”.

๊ทธ๋ฆฌ๊ณ  ์•„๋งˆ ๋ณดํ†ต ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ weak์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๋ณดํŽธ์ ์ผ ๊ฑฐ์—์š”!

 

์ด๋ ‡๊ฒŒ Swift์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ, ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํฌ์ธํŠธ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ์•Œ์•„๋ณด์•˜๋Š”๋ฐ์š”!!

์˜ค๋Š˜์€ ์ข€ ๋ณต์žกํ•˜์ง€๋งŒ ๋งค์šฐ ์ค‘์š”ํ•œ ๊ฐœ๋…์„ ์ •๋ฆฌํ•ด๋ดค๋Š”๋ฐ, ํ‹ˆํ‹ˆํžˆ ๋‹ค์‹œ ๋ณด๋ฉด์„œ ์žŠ์ง€ ๋ง์•„์•ผ๊ฒ ์–ด์š”. ๐Ÿ‘๐Ÿ‘

์˜ค๋Š˜๋„ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋„์›€์ด ๋˜์—ˆ๊ธธ ๐Ÿ™

Comments