참조 카운트 예제
class Person {
let testCase: String
init(testCase: String) {
self.testCase = testCase
}
deinit {
print("\(testCase) is being deinitialized")
}
}
// ### case 1. Allocation & Release
print("\n---------- [ Case 1 ] ----------\n")
var obj1: Person? = Person(testCase: "case1")
obj1 = nil
//### case 2. 참조 카운트 증가
print("\n---------- [ Case 2 ] ----------\n")
var obj2: Person? = Person(testCase: "case2") //count 1
var countUp = obj2 // count 2
obj2 = nil // count1
countUp = nil // count0
// case 3. Collection 에 의한 참조 카운트
print("\n---------- [ Case 3 ] ----------\n")
var obj3: Person? = Person(testCase: "case3") // count1
var array = [obj3, obj3] //count2, count3
obj3 = nil // count2
array.remove(at: 0) // count1
array.remove(at: 0) // count0
@참조의 종류
print("\n---------- [ Case 4 ] ----------\n")
var strongObj4 = Person(testCase: "case4") //count1
print(strongObj4)
weak var weakObj4 = Person(testCase: "case4") //count up이 되지 않음
print(weakObj4)
unowned var unownedObj4 = Person(testCase: "case4") // 생성하자마자 사라짐
print(unownedObj4)
class LocalScope {
func doSomething() {}
deinit {
print("LocalScope is being deinitialized")
}
}
class ClassProperty {
func doSomething() {}
deinit {
print("ClassProperty is being deinitialized")
}
}
class Application {
var prop = ClassProperty() // count1
func allocateInstance() {
let local = LocalScope() // count1
local.doSomething()
}
deinit {
print("Application is being deinitialized")
}
}
// Q. 아래의 코드 실행 시 출력되는 메시지는?
var app: Application? = Application() //count1 -> classproperty count1
app?.prop.doSomething()
app?.allocateInstance() // count1 -> count0
// Q. ClassProperty 객체의 deinit 메서드가 호출되려면 어떻게 할까요?
app = nil // app이 가르키던 주소가 0 -> Application count 0 -> ClassProperty count0
class Person {
var pet: Dog?
func doSomething() {}
deinit {
print("Person is being deinitialized")
}
}
class Dog {
var owner: Person?
func doSomething() {}
deinit {
print("Dog is being deinitialized")
}
}
var giftbot: Person! = Person() // count1
var tory: Dog! = Dog() // count1
giftbot.pet = tory // dog count2
tory.owner = giftbot // person count2
giftbot.doSomething()
tory.doSomething()
//giftbot = nil // person count1
//tory = nil // dog count1 -> 참조순환으로 메모리에 남아있음
// 그래서!
giftbot.pet = nil
//tory.owner = nil
giftbot = nil
tory = nil
// 큰단위의 메모리부터 해제하면 메모리 속 데이터에 접근방법을 잃어버리기 때문에 데이터부터 접근하여 제거해야 함!
class Teacher {
var student: Student?
deinit {
print("Teacher is being deinitialized")
}
}
class Student {
// strong, unowned, weak
// let teacher: Teacherc // count2
unowned let teacher: Teacher // teacher count1
// weak var teacher: Teacher? // weak은 필히 optional로 선언하기
init(teacher: Teacher) {
self.teacher = teacher
}
deinit {
print("Student is being deinitialized")
}
}
var teacher: Teacher? = Teacher() // teacher count1
var student: Student? = Student(teacher: teacher!)
teacher?.student = student // teacher count2
print("\n---------- [ teacher release ] ----------\n")
teacher = nil // teacher count0 -> student count1
print("\n---------- [ student release ] ----------\n")
student = nil // student count 0
// 1) strong : 명시적으로 nil 대입 필요. teacher?.student = nil
// 2) unowned : 자동으로 deinit. nil 처리 된 속성에 접근하면 런타임 에러 발생
// 3) weak : 자동으로 deinit. nil 처리 된 속성에 접근하면 nil 반환