일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- stanford
- 프로젝트회고
- Swift
- flutter #state # stateful #stateless
- CS193p
- xcode
- GIT
- xml
- 청년취업사관학교후기
- 코딩테스트
- flutter
- IOS
- WidgetTree
- collectionView
- Masil
- ImageSlider
- SwiftUI
- UIKit
- UserDefault
- process
- MVVM
- 새싹후기
- 백준
- 조건문
- 스위프트
- 알고리즘
- 프로그래머스
- 스터디
- colorofdays
- 오늘의 색상
- Today
- Total
개발을 시작하는 이야기
weak, unowned 본문
Swift의 ARC는 레퍼런스 카운트를 관리하여 메모리 누수를 방지하는 역할을 한다.
이때, 인스턴스끼리의 강한 순환 참조 문제를 해결하는 두 가지 방법이 있는데
weak reference와 unowned reference를 사용하는 것이다.
Weak References
weak references는 참조하는 인스턴스를 강하게 유지하지 않는 참조로 ARC가 참조된 인스턴스를 할당 해제할 수 있다.
할당 해제가 되면 ARC는 자동으로 약한 참조를 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") }
}
ARC 글에서 살펴보았던 예시와 동일하지만, Apartment 클래스의 tenant 변수를 weak로 선언을 해주었다.
이 차이가 어떤 결과를 가져오는지 살펴보자
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
두 변수의 강한 참조와 두 인스턴스 간의 링크는 이전과 같이 생성한다.
Apartment 인스턴스는 Person 타입의 변수인 tenant을 weak로 선언해줬기 때문에 person 인스턴스에 약한 참조를 갖고 있다.
john = nil
// Prints "John Appleseed is being deinitialized"
즉, john을 nil로 설정하여 john과 Person 인스턴스 사이의 강한 참조를 끊게 되면 더 이상 Person 인스턴스에는 강한 참조가 없어진다.
Person 인스턴스에 대해 더이상 참조가 없기 때문에 할당이 해제되고, Apartment 인스턴스의 tenant도 nil로 설정된다.
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
unit4A 변수도 nil로 설정하게 되면
Apartment 인스턴스에 대한 강한 참조까지도 끊어지고 할당이 해제된다.
Unowned References
위에서 봤던 weak reference처럼 unowned reference도 인스턴스 간에 강한 참조를 유지하지 않는다.
하지만 unowned reference는 weak reference와 달리 다른 인스턴스의 수명이 동일하거나 길 때 사용되며, 항상 값이 있어야 하기 때문에 옵셔널이 아닌 상수로 선언한다.
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") }
}
Customer 클래스에는 옵셔널 타입으로 CreditCard 속성이 있고,
CreditCard 클래스에는 unowned 키워드가 붙은 상수로 Custom 속성을 갖고 있다.
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
Customer 인스턴스로 john을 만들고 john의 card 속성에 CreditCard 인스턴스를 할당하면 다음과 같은 참조 관계가 생성된다.
Customer 인스턴스는 CreditCard 인스턴스에 강한 참조를 갖고,
CreitCard 인스턴스는 소유하지 않은 Customer 인스턴스에 대한 미소유 참조를 갖는다.
이제 john에 nil값을 할당해 강한 참조를 깨면, Customer 인스턴스에 대한 강한 참조가 더 이상 없어지게 된다.
따라서, Customer 인스턴스에 대한 참조가 더 이상 없어지므로 할당이 해제되고,
CreditCard 인스턴스에 대한 강한 참조도 더 이상 없어지므로 할당 해제된다.
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"
Swift를 처음 배우기 시작했을 때, Xcode의 Storyboard에서 Outlet을 연결할 때
strong과 weak를 선택할 때 그냥 weak로 하면 된다 하고 넘어갔었는데 이제는 어째서인지 학습을 하게 되었다.
이론적으론 이해가 되었지만 사실 코드에서 완벽하게 적용하기에는 아직 미흡하다.
코드를 작성할 때 이런 작은 부분도 고려해가면서 작성하는 연습을 해야겠다.
참고 : https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
'개발 이야기 > Swift' 카테고리의 다른 글
@main (0) | 2022.03.21 |
---|---|
앱 시닝(app thinning) (0) | 2022.03.20 |
ARC(Automatic Reference Counting) (0) | 2022.03.18 |
ViewController (0) | 2022.03.17 |
앱의 콘텐츠나 데이터 자체를 저장/보관하는 객체들 (0) | 2022.03.16 |