์ค๋์ ARC ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ๋ํด์ ๊ณต๋ถํด ๋ณผ๊น ํฉ๋๋ค!
๊ทธ๋ผ ์์ํด ๋ณผ๊น์?! โจ
์ค์ํํธ๋ ARC ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ํ ์์ญ์์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
์.. ๊ทธ๋ ๋ค๋ฉด ํ ์์ญ์ด ๋์ฒด ๋ญ๊ธธ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ ํ ๊น์?!
๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ ์ค Heap ์์ญ
Heap ์์ญ์ ๋ฐํ์ ์ค ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด ํ์ํ ๊ฒฝ์ฐ์ ๋์ ์ผ๋ก ํ ๋น๋ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋๋ ๊ณณ์ ๋๋ค. ๊ทธ๋ผ ๋์ ํ ๋น์ด ๋ญ๋ฐ์?! ๋์ ํ ๋น์ด๋ ์คํ ์์ญ์ฒ๋ผ ์ ํด์ง ๊ณณ์ ๋ฐ์ดํฐ ๋ฑ๋ฑ ๋ค์ด๊ฐ๊ณ ๋์ค๋ ๊ฒ์ด ์๋๋ผ ๋ฉ๋ชจ๋ฆฌ์ ๋น์์ ธ ์๋ ๊ณต๊ฐ์ ์ฐพ์์ ํฌ๊ธฐ๋ ์์กด๊ธฐ๊ฐ์ ์ ํ์ฌ ํ ๋นํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋๋ค. Heap ์์ญ์๋ ์ฐธ์กฐ ํ์ ์ ๋ฐ์ดํฐ๋ง ์ ์ฅ์ด ๋ฉ๋๋ค.
- ๋ฐํ์ ์ค ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด ํ์ํ ๊ฒฝ์ฐ Heap ์์ญ์ ์ ์ฅ
- ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋์ ์ผ๋ก ํ ๋น
- ์ฐธ์กฐ ํ์ ์ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ
์ด Heap ์์ญ์ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ์ด ๋๋ฉด ๋ ์ด์ ํด๋น ๋ฐ์ดํฐ๊ฐ ํ์ ์์ ๋๋ ๋ฉ๋ชจ๋ฆฌ์์ ๋ฐ์ดํฐ๋ฅผ ํด์ ๋ฅผ ํด์ฃผ์ด์ผ ํ์์์?!
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด Heap ์์ญ์ ๊ฐ๋ฐ์๊ฐ ๋ฐ์ดํฐ ๊ด๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ๋ง ํฉ๋๋ค.
ARC ( Automatic Reference Counting )
์ค์ํํธ๋ ๊ฐ๋ฐ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด์ ARC๋ผ๋ ๋ชจ๋ธ์ ์ฌ์ฉํฉ๋๋ค. ARC๋ ' Automatic Reference Counting '์ด๋ผ๋ ์์ด์ ์ค์๋ง์ธ๋ฐ์! Reference Counting์ ์๋์ผ๋ก ๊ด๋ฆฌํด ์ฃผ๋ ๋ชจ๋ธ์ ๋๋ค.
Reference Counting
์ฌ๊ธฐ์ Referece Counting์ด๋ ์๊ธฐ ์์ ์ ๊ฐ๋ฆฌํค๊ณ ์๋ ( ์ฐธ์กฐํ๊ณ ์๋ ) ๊ฒ์ ๊ฐ์์ ๋๋ค. ์ค์ฌ์ RC๋ผ๊ณ ๋ ํด์.
ARC๋ ๋ค๋ฅธ ๋ชจ๋ธ๋ค๊ณผ ๋ฌ๋ฆฌ RC๋ฅผ 1 ์ฆ๊ฐ์์ผ ์ฃผ๋ retain()
ํจ์์ RC๋ฅผ 1 ๊ฐ์์์ผ์ฃผ๋ release()
ํจ์๋ฅผ ์๋์ผ๋ก ์คํ์์ผ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ด๋ฆฌํด ์ค๋๋ค. ๊ทธ๋ ๋ค๋ฉด, ๊ฐ๋ฐ์๋ค์ด ์ธ์ , ์ด๋ป๊ฒ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ ํ ๊น์?!
๊ฐํ ์ฐธ์กฐ ์ฌ์ดํด
์๋ก ๋ค๋ฅธ ์ธ์คํด์ค๊ฐ ์๋ก๋ฅผ ๊ฐ๋ฆฌํฌ ๋๋ฅผ Strong Reference Cycle ์ด๋ผ๊ณ ํ๋ฉฐ, ์ด๋ฅผ ๊ฐํ ์ฐธ์กฐ ์ฌ์ดํด์ด๋ผ๊ณ ํ๋๋ฐ์. ์ด๋, ๊ฐ๊ฐ์ ์ธ์คํด์ค๊ฐ nil์ด ๋์ด๋ ์๋ก๊ฐ ์๋ก๋ฅผ ์ฐธ์กฐํ๊ณ ์๊ธฐ ๋๋ฌธ์ RC๊ฐ 0์ด ๋์ง ๋ชปํด์ ๋ฉ๋ชจ๋ฆฌ์ ๊ณ์ ๋จ์์๋ ์ํฉ์ ๋๋ค. ์ฐ์ด์ง ์๋๋ฐ, ๋ฉ๋ชจ๋ฆฌ์ ๊ณ์ ๋จ์์๊ฒ ๋๋ฉด ์ด๋ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๊ฐ ๋๊ฒ ์ฃ ? ์ด๋ฅผ "๋ฉ๋ชจ๋ฆฌ ๋์"๊ฐ ๋ฐ์ํ๋ค๊ณ ํฉ๋๋ค.
์กฐ๊ธ ๋ ์์ธํ ์์๋ฅผ ํตํด ์์๋ด ์๋ค!
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
print("Apartment \(unit) is being initialized")
}
deinit {
print("Apartment \(unit) is being deinitialized")
}
}
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
์์ ์ฝ๋๋ฅผ ๊ฐ๋จํ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ด๋ฉด ์๋์ฒ๋ผ ๋ํ๋ผ ์ ์์ต๋๋ค. Person๊ณผ Apartment๋ผ๋ ํด๋์ค์ ์ธ์คํด์ค๊ฐ ๊ฐ๊ฐ john๊ณผ unit4A์ด๊ณ ์ธ์คํด์ค์ ์ ์ฅ ์์ฑ์ธ apartment์ tenant๊ฐ ๊ฐ๊ฐ์ ํด๋์ค๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ต๋๋ค.
์ด๋, john์ด๋ผ๋ Person์ ์ธ์คํด์ค๋ john์ด๋ผ๋ ๋ณ์์๊ฒ์ ์ฐธ์กฐ๋ฅผ ๋นํ๊ณ , unit4A์ ์ ์ฅ ์์ฑ์ธ tenant์๊ฒ ์ฐธ์กฐ๋นํ๊ณ ์๊ธฐ ๋๋ฌธ์ RC๊ฐ 2๋ผ๊ณ ํ ์ ์์ต๋๋ค. unit4A๋ผ๋ Apartment์ ์ธ์คํด์ค๋ ๋ง์ฐฌ๊ฐ์ง๋ก RC๊ฐ 2์ด๊ฒ ์ฃ ?!
์ด ๊ฒฝ์ฐ์ john๊ณผ unit4A์ ๊ฐ์ nil๋ก ํ ๋นํ๊ฒ ๋๋ฉด, john๊ณผ unit4A๊ฐ ์ฐธ์กฐํ๊ณ ์๋ ํด๋์ค๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ์ด๋ฏ๋ก ๊ฐ๊ฐ์ RC๊ฐ 1๋ก ์ค์ด๋ค๊ฒ ๋ฉ๋๋ค.
์ด๋, ์๋ก๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์๋ ์ฐธ์กฐ๊ฐ ๋จ์์์ด RC๊ฐ 1์ธ ์ํ๋ก ์ ์ง๋๊ธฐ ๋๋ฌธ์ Heap ์์ญ์์ John๊ณผ unit4A์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ๊ฑฐ๋์ง ์์ต๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋์๊ฐ ๋ฐ์ํ๊ฒ ๋๊ณ , ์ด๋ฐ ์ํฉ์ ๊ฐํ ์ฐธ์กฐ ์ฌ์ดํด์ด๋ผ๊ณ ํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด์ ์ด๋ป๊ฒ ํด์ผ ํ ๊น์?!?!
๊ฐํ ์ฐธ์กฐ ์ฌ์ดํด๋ก ์ธํ ๋ฉ๋ชจ๋ฆฌ ๋์์ ํด๊ฒฐ๋ฐฉ์์ ๋ ๊ฐ์ง๊ฐ ์์ต๋๋ค.
์ฝํ ์ฐธ์กฐ ( weak Reference )
์ฒซ ๋ฒ์งธ๋ก๋ ์ฝํ ์ฐธ์กฐ์
๋๋ค. ์ฐธ์กฐ๋ฅผ ๋นํ๋ ์ธ์คํด์ค๊ฐ nil
์ด ๋๋ฉด ์ฐธ์กฐํ๋ ์ธ์คํด์ค๋ nil
๋ก ํ ๋น์ด ๋๋๋ก ํ๋ ๊ฒ์
๋๋ค.
weak
ํค์๋ ์ฌ์ฉ
class Person {
var name: String
weak var friend: Person? // ์ฝํ ์ฐธ์กฐ
init(name: String) {
self.name = name
}
}
var john: Person? = Person(name: "John")
var doe: Person? = Person(name: "Doe")
john?.friend = doe
doe?.friend = john
john = nil
doe = nil
์์ ์์๋ก ์ค๋ช
ํ์๋ฉด, john์ ๊ฐ์ด nil
์ด ๋๋ค๋ฉด ์ด john์ ๊ฐ๋ฆฌํค๋ unit4A์ ์ ์ฅ์์ฑ์ธ tenant์ ๊ฐ๋ nil
์ด ๋์ด RC๊ฐ 0์ผ๋ก ์ค์ด ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๊ฐ ๋ฉ๋๋ค!
๋น์์ ์ฐธ์กฐ ( unowned Reference )
weak
๊ณผ ๋น์ทํ์ง๋ง, ๋ค๋ฅธ ๋ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ๋น์์ ์ฐธ์กฐ์
๋๋ค. weak
๊ณผ ๋ค๋ฅธ ์ ์ ์ต์
๋ ํ์
์ด ์๋๊ธฐ ๋๋ฌธ์ ์ฐธ์กฐ๋นํ๋ ์ธ์คํด์ค๊ฐ nil
์ด ๋๋ฉด ์ฐธ์กฐํ๋ ์ธ์คํด์ค๋ฅผ ํธ์ถํ์์ ๋, ์ค๋ฅ๊ฐ ๋ฉ๋๋ค. ๊ทธ๋์ ๊ฐ์ด ์์ ๊ฒ์ด๋ผ๋ ๊ฒ์ด ๋ช
ํํด์ง ๋ ์ฌ์ฉํ๋ ๊ฒ์ด ๋น์์ ์ฐธ์กฐ์
๋๋ค.
unowned
ํค์๋
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer //๋น์์ ์ฐธ์กฐ
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
}
var john: Customer? = Customer(name: "John Doe")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil // ์ฌ๊ธฐ์ Customer ์ธ์คํด์ค์ ์ฐ๊ด๋ CreditCard ์ธ์คํด์ค๋ ํจ๊ป ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋ฉ๋๋ค.
์์ ๊ฒฝ์ฐ์ CreditCard์ ์ธ์คํด์ค๋ customer(john)์ด nil๋ก ํ ๋น๋์ง ์์ ๋๋ง ์ ํจํ๊ณ , Customer ์ธ์คํด์ค๊ฐ nil์ด ๋ ํ์ CreditCard๋ฅผ ํธ์ถํ๋ฉด ๋ฐํ์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
weak VS unowned
- ๋ณดํต weak์ ๋ ๋ง์ด ์ฌ์ฉ
- weak ๋ณด๋ค unowned๊ฐ ๋ ๋น ๋ฆ.
[ let, var, optional, non-optional ์ฌ์ฉ ๊ฐ๋ฅ ]
let | var | optional | non-optional | |
strong | O | O | O | O |
weak | X | O | O | X |
unowned | O | O | O | O |
์ด๋, strong์ ๊ธฐ๋ณธ ๋ณ์ ์ ์ธ ์์ ์๋์ผ๋ก ์ ์ธ๋๋ ํค์๋์ ๋๋ค.