[Swift] ์๋ ์ฐธ์กฐ ์นด์ดํธ
์๋ ์ฐธ์กฐ ์นด์ดํธ(ARC, Automatic Reference Counting)
- ์ฑ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉ
- ์๋์ผ๋ก ์ฐธ์กฐ ํ์๋ฅผ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ์ ๊ฒฝ์ธ ํ์๊ฐ ์๊ณ ARC๊ฐ ์๋์ผ๋ก ์ฌ์ฉํ์ง ์๋ ์ธ์คํด์ค๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ง
- ํน์ ๊ฒฝ์ฐ์ ARC์์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ์ํด ์ฝ๋์ ํน์ ๊ด๊ณ์ ๋ํ ์ ๋ณด๋ฅผ ํ์๋ก ํจ
- ์ฐธ์กฐ ํ์๋ ํด๋์ค ํ์ ์ ์ธ์คํด์ค์๋ง ์ ์ฉ๋๊ณ ๊ตฌ์กฐ์ฒด, ์ด๊ฑฐํ ๋ฑ ๊ฐ ํ์ ์๋ ์ ์ฉ๋์ง ์์
ARC ๋์
- ์๋ก์ด ํด๋์ค ์ธ์คํด์ค๋ฅผ ๋ง๋ค ๋ ๋ง๋ค ARC๋ ์ธ์คํด์ค ์ ๋ณด๋ฅผ ๋ด๋๋ฐ ํ์ํ ํฌ๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น
- ๋ฉ๋ชจ๋ฆฌ๋ ์ธ์คํด์ค์ ๋ํ ์ ๋ณด์ ๊ด๋ จ๋ ์ ์ฅ ํ๋กํผํฐ ๊ฐ์ ๊ฐ๊ณ ์์
- ์ธ์คํด์ค๊ฐ ๋์ด์ ์ฌ์ฉ๋์ง ์์ ๋ ARC๋ ๊ทธ ์ธ์คํด์ค๊ฐ ์ฐจ์งํ๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์งํด ๊ณต๊ฐ์ ํ๋ณด
- ARC๋ ์์ง ์ฌ์ฉ์ค์ธ ์ธ์คํด์ค๋ฅผ ํด์งํ์ง ์๊ธฐ ์ํด ํ๋๋ผ๋ ์ฐธ์กฐ๊ฐ ์๋ ๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ์์ ํด์งํ์ง ์์
ARC ์ฌ์ฉ
class Person {
let name: String
init(name: String) {
self.name = name
print("\\(name) is being initialized")
}
deinit {
print("\\(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"
reference2 = reference1
reference3 = reference1
ํ์ฌ Person ์ธ์คํด์ค์ ๋ํ ์ฐธ์กฐ ํ์๋ 3
reference1 = nil
reference2 = nil
ํ์ฌ Person ์ธ์คํด์ค์ ๋ํ ์ฐธ์กฐ ํ์๋ 1
reference3 = nil
// Prints "John Appleseed is being deinitialized"
Person์ธ์คํด์ค๋ฅผ ์ฐธ์กฐํ๊ณ ์๋ ๊ฒ์ด ์์ผ๋ฏ๋ก ARC๊ฐ Person ์ธ์คํด์ค๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ง
ํด๋์ค ์ธ์คํด์ค๊ฐ ๊ฐํ ์ฐธ์กฐ ์ํ
ํด๋์ค์ ์ธ์คํด์ค๊ฐ ๊ฐํ๊ฒ ์ํธ์ฐธ์กฐํ๊ณ ์๋ ๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋์ง ์์
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(name: "John Appleseed")
var unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
๋ ๊ฐ์ ํด๋์ค๊ฐ ์๋ก ์ธ์คํด์ค๋ฅผ ์์ ํ๊ณ ์๋๊ฒฝ์ฐ ์๋ก๋ฅผ ์ฐธ์กฐํ๊ฒ๋๊ณ , nil์ ํ ๋นํด ํ์กฐ๊ฐ ํด์งํ๋ ค๊ณ ํ๋๋ผ๋ ๋ ์ธ์คํด์ค๋ ํด์ง๋์ง ์์
๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ์
๊ฐํ ์ฐธ์กฐ ์ํ ๋ฌธ์ ํด๊ฒฐ
์ฝํ ์ฐธ์กฐ
์ฝํ ์ฐธ์กฐ๋ก ์ ์ธํ๋ฉด ์ฐธ์กฐํ๊ณ ์๋ ๊ฒ์ด ๋จผ์ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ง๋๊ธฐ ๋๋ฌธ์ ๋ฐํ์์ ์๋์ผ๋ก ์ฐธ์กฐํ๊ณ ์๋ ๋ณ์์ nil ํ ๋น
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 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
john = nil
// Prints "John Appleseed is being deinitialized"
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
๋ฏธ์์ ์ฐธ์กฐ
์ฐธ์กฐ ๋์์ด ๋๋ ์ธ์คํด์ค๊ฐ ํ์ฌ ์ฐธ์กฐํ๊ณ ์๋ ๊ฒ๊ณผ ๊ฐ์ ์์ ์ฃผ๊ธฐ๋ฅผ ๊ฐ๊ฑฐ๋ ๋ ๊ธด ์์ ์ฃผ๊ธฐ๋ฅผ ๊ฐ๊ธฐ ๋๋ฌธ์ ํญ์ ์ฐธ์กฐ์ ๊ทธ ๊ฐ์ด ์๋ค๊ณ ๊ธฐ๋๋จ
๋ฐ๋ผ์ ARC๋ ๋ฏธ์์ ์ฐธ์กฐ์๋ ์ ๋ 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") }
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"
๋ฏธ์์ ์ฐธ์กฐ์ ์์์ ์ต์ ๋ ํ๋กํผํฐ ์ธ๋ํ
๋ ํ๋กํผํฐ๊ฐ ํญ์ ๊ฐ์ ๊ฐ์ง๋ง ํ๋ฒ ์ด๊ธฐํ ๋๋ฉด ์ ๋ nil์ด ๋์ง ์๋ ๊ฒฝ์ฐ ๋ฏธ์์ ํ๋กํผํฐ๋ฅผ ์์์ ์ต์ ๋ ํ๋กํผํฐ ์ธ๋ํ์ ์ฌ์ฉํด ์ฐธ์กฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐ
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String) {
self.name = name
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
}
}
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"
ํด๋ก์ ์์์ ๊ฐํ ์ฐธ์กฐ ์ํ
ํด๋ก์ ์์๋ self๋ฅผ ์บก์ณํ๊ธฐ ๋๋ฌธ์ ๊ฐํ ์ฐธ์กฐ ์ํ์ด ๋ฐ์ํ ์ ์์
ํด๋ก์ ์์ ๊ฐํ ์ฐธ์กฐ ์ํ ๋ฌธ์ ํด๊ฒฐ
์บก์ณ ์ฐธ์กฐ์ ๊ฐํ ์ฐธ์กฐ ๋์ ์ฝํ ์ฐธ์กฐ ํน์ ๋ฏธ์์ ์ฐธ์กฐ ์ง์ ๊ฐ๋ฅ
์บก์ณ๋ฆฌ์คํธ ์ ์
ํด๋ก์ ์ ํ๋ผ๋ฏธํฐ ์์ ์๊ดํธ๋ฅผ ๋ฃ๊ณ ๊ทธ ์์ ๊ฐ ์บก์ณ ๋์์ ๋ํ ์ฐธ์กฐ ํ์์ ์ ์
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}