약한 참조
- 강한 참조와 달리 자신이 참조하는 인스턴스의 참조 횟수를 증가시키지 않음
- 참조 타입의 프로퍼티나 변수의 선언 앞에
weak 키워드
를 사용하면 그 프로퍼티나 변수는 자신이 참조하는 인스턴스를 약한 참조함 - 약한 참조를 사용하면 자신이 참조하는 인스턴스가 메모리에서 해제될 수 도 있다는 것을 예상할 수 있음
- 참조하는 인스턴스에 대한 참조를 강하게 유지하지 않기 때문에 약한 참조로 참조되고 있는 동안에도 해당 인스턴스가 할당 해제될 수 있음
ARC
는 인스턴스가 할당 해제될 때 해당 인스턴스를 약한 참조하는 프로퍼티를nil
로 초기화함- 때문에 약한 참조는 항상 옵셔널 변수에만 사용 가능하며, 약한 참조는 상수에서 쓰일 수 없음
약한 참조와 상수, 옵셔널
만약 자신이 참조하던 인스턴스가 메모리 해제되면 nil
이 할당될 수 있어야 하기 때문에 약한 참조는 상수에서 쓰일 수 없다. 그래서 약한 참조를 할 땐 자신의 값을 변경할 수 있는 변수로 선언해야 한다. 또, nil
이 할당될 수 있어야 하므로 약한참조는 당연히 항상 옵셔널
이여야 한다. 즉, 옵셔널 변수에만 약한참조
를 할 수 있다.
강한 참조 순환에서 사용했던 코드
<hide/>
class Person {
let name: String
init(name: String) {
self.name = name
}
var room: Room?
deinit {
print("\(name) is being deinitialized!")
}
}
class Room {
let number: String
init(number: String) {
self.number = number
}
var host: Person?
deinit {
print("Room \(number) is being deinitialized!")
}
}
var seogun: Person? = Person(name: "서근") // Person 인스턴스의 참조 횟수 : 1
var myRoom: Room? = Room(number: "50") // Room 인스턴스의 참조 횟수 : 1
seogun?.room = myRoom // Room 인스턴스의 참조 횟수 : 2
myRoom?.host = seogun // Person 인스턴스의 참조 횟수 : 2
seogun?.room = nil // Room 인스턴스의 참조 횟수 : 1
myRoom?.host = nil // Person 인스턴스의 참조 횟수 : 1
seogun = nil // Person 인스턴스의 참조 횟수 : 0
// 서근 is being deinitialized!
myRoom = nil // Room 인스턴스의 참조 횟수 : 0
// Room 50 is being deinitialized!
강한 참조 순환에서 사용했던 Room
클래스에서 host
프로퍼티를 약한 참조로 바꿔보면 다음과 같다.
class Person {
let name: String
init(name: String) {
self.name = name
}
var room: Room?
deinit {
print("\(name) is being deinitialized!")
}
}
class Room {
let number: String
init(number: String) {
self.number = number
}
//var host: Person?
weak var host: Person?
deinit {
print("Room \(number) is being deinitialized!")
}
}
그리고 seogun
과 myRoom
의 관계는 이러했다.
var seogun: Person? = Person(name: "서근") // Person 인스턴스의 참조 횟수 : 1
var myRoom: Room? = Room(number: "50") // Room 인스턴스의 참조 횟수 : 1
seogun?.room = myRoom // Room 인스턴스의 참조 횟수 : 2
myRoom?.host = seogun // Person 인스턴스의 참조 횟수 : 1 (약한 참조니까!!!!)
Person
인스턴스는 Room
인스턴스에 대에 강한 참조를 여전히 유지하고 있는데 반해, Room
인스턴스는 Person
인스턴스에 대해 약한 참조를 가지게 됐다.
이는 seogun
변수에 nil
을 할당해 Person
인스턴스에 대한 강한 참조를 해제하게 된다면, Person
인스턴스는 더 이상 강한 참조를 갖지 않게 된다.
그러니까 Person
과 Room
클래스는 둘 다 강한 참조이고, myRoom
변수가 Room
인스턴스에 강한 참조 했고, 이것을 Person
인스턴스에 약한 참조로 전달했으니(참조 횟수 증가 안 함) Person
인스턴스는 var seogun
변수를 제외한 모든 인스턴스가 약한 참조인 것!
여기서 유일한 강한 참조인 var seogun
에 nil
을 주면?
더 이상 Person
인스턴스에 대한 강한 참조가 존재하지 않으므로, Person
인스턴스가 할당 해제 되었고, Person
인스턴스에 대해 약한 참조를 가지고 있던 host
프로퍼티는 nil
이 된다.
print(myRoom?.host) //옵셔널 Person
seogun = nil // Person 인스턴스 참조 횟수 : 0 , Room 인스턴스의 참조 횟수 : 1
//서근 is being deinitialized!
print(myRoom?.host) //nil
왜 host
가 nil
이냐? Person
이 존재 하지 않으니까!
weak var host: Person? //Person이 존재하지 않으니까 host도 nil
이렇게 Room
인스턴스에 대한 강한 참조는 myRoom
변수가 가지는 강한 참조만 남게 된다. 이 강한 참조 마저 해제해 버린다면? Room
인스턴스는 더 이상 강한 참조를 가지지 않게 되면서 디이니셜라이저를 호출한다.
myRoom = nil // Room 인스턴스의 참조 횟수 : 0
//Room 50 is being deinitialized!
전체적인 코드를 보면 이러하다.
class Person {
let name: String
init(name: String) {
self.name = name
}
var room: Room?
deinit {
print("\(name) is being deinitialized!")
}
}
class Room {
let number: String
init(number: String) {
self.number = number
}
weak var host: Person?
deinit {
print("Room \(number) is being deinitialized!")
}
}
var seogun: Person? = Person(name: "서근") // Person 인스턴스의 참조 횟수 : 1
var myRoom: Room? = Room(number: "50") // Room 인스턴스의 참조 횟수 : 1
seogun?.room = myRoom // Room 인스턴스의 참조 횟수 : 2
myRoom?.host = seogun // Person 인스턴스의 참조 횟수 : 1 (약한 참조니까!!!!)
print(myRoom?.host) //옵셔널 Person
seogun = nil // Person 인스턴스의 참조 횟수 : 0 , Room 인스턴스의 참조 횟수 : 1
//서근 is being deinitialized!
print(myRoom?.host) //nil
myRoom = nil // Room 인스턴스의 참조 횟수 : 0
//Room 50 is being deinitialized!
다음 게시글은 미소유 참조에 대해 알아보도록 하겠습니다.
읽어주셔서 감사합니다 🤟
'SWIFT > Grammar' 카테고리의 다른 글
Swift 기초 문법 모음 (9) | 2022.02.24 |
---|---|
Swift : 고급문법[ARC 메모리 관리4 - 미소유 참조(unowned)] (0) | 2022.02.19 |
Swift : 고급문법 [ARC 메모리 관리 2 - 강한 참조 순환 문제] (0) | 2022.02.12 |
Swift : 고급문법 [ARC 메모리 관리 1 - 강한 참조] (0) | 2022.02.10 |
Swift: 기초문법 [데이터 타입 - Int와 UInt (feat.카멜케이스)] (4) | 2022.02.09 |