Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- App Clip
- DooC
- METAL
- SF Symbols
- NSUserActivity
- concurrency
- ProRAW
- SF Symbols 3.0
- Mac
- async
- Object Capture
- Reality Composer
- Xcode Organizer
- AppleEvent
- Xcode Cloud
- User Enrollment
- swiftUI
- Physical Audio
- MDM
- Hand Action Detect
- AVFoundation
- Hand Pose Detect
- AR Quick Look
- CoreML
- detent
- WWDC 2021
- SWiFT
- profile
- DriverKit
- actor
Archives
- Today
- Total
nyancoder
WWDC 2021 - ARC in Swift: Basics and beyond 본문
원본 영상: https://developer.apple.com/videos/play/wwdc2021/10216/
Object lifetimes and ARC
- 객체의 수명은 init()에서 시작하여 마지막 접근 이후 끝납니다.
- ARC는 수명이 끝난 객체의 메모리를 자동 해제합니다.
- ARC는 참조 횟수를 추적하여 개체의 수명을 결정합니다.
- Swift 컴파일러는 ARC를 위해 retain/release 연산을 추가합니다.
- 참조 횟수가 0으로 떨어진 객체는 할당 해제됩니다.
- Traveler 객체는 생성되었을 때 ref_count가 1로 만들어집니다.
- traveler1에서 traveler2에 객체가 할당되었을 때, retain이 불리며 ref_count가 1 증가하여 2가 됩니다.
- 이후 traveler1은 더 이상 참조되지 않으므로 release가 호출되면서 ref_count가 1 감소하여 1이 됩니다.
- traveler2도 더 이상 참조되지 않게 되면 release가 호출되면서 ref_count가 1 감소하여 0이 됩니다.
- 컴파일러에 의해 추가된 release연산에 의해 ref_count가 0이 되면 오브젝트가 해제됩니다.
- 최적화 옵션에 의해서 release연산이 마지막 사용 이후에 있을 수 있으며 이때에는 더 늦게 해제될 수 있습니다.
- weak나 unowned 참조나 deinit과 같은 기능을 통해서 객체의 수명을 확인할 수 있습니다.
- 객체의 수명에 의존하는 코드는 버그를 만들 수 있습니다.
- 이러한 버그는 오랜 기간 동안 발견되지 않을 수 있으며, 컴파일러의 업데이트나 컴파일러의 최적화와 연관된 다른 부분의 소스의 변경에도 영향을 받을 수 있습니다.
Observable object lifetime
- weak나 unowned 참조는 참조 횟수를 세는데 영향을 주지 않기 때문에, 주로 순환 참조를 막는 데 사용됩니다.
- 순환 참조란, Traveler.account가 가리키는 Account의 Account.traveler가 다시 처음의 Traveler를 가리키는 것과 같은 현상을 말합니다.
- 이 경우에는 test함수가 종료되어도 각각의 객체의 ref_count가 1 미만으로 내려가지 않기 때문에 객체가 해제되지 않습니다.
- weak나 unowned 참조는 참조 횟수를 세는데 영향을 주지 않기 때문에, 순환 참조를 막을 수 있습니다.
- 대신 참조하고 있는 객체가 해제될 수 있기 때문에 해제된 객체에 대해 접근할 때에 대한 별도의 처리가 있습니다.
- weak 참조는 대상이 해제되면 nil이 되도록 처리되어 있습니다.
- unowned 참조는 대상이 해제된 상태에서 접근하는 것을 탐지하여 오류를 발생합니다.
위의 예제에서는 Account의 traveler를 weak 참조로 변경하여 프로그램이 종료될 때 traveler가 해제될 수 있습니다.
- account.printSummary()를 호출하면 traveler의 마치 막 참조 이후에 traveler를 참조하는 것이기 때문에 오류가 발생할 수 있습니다.
- 오류를 막기 위해 printSummary() 함수 내에서 nil 체크를 수행할 수 있지만, 크래시만 발생하지 않을 뿐 여전히 버그로 남을 수 있습니다.
- withExtendedLifetime() 함수를 사용하면 명시적으로 객체의 수명을 특정 시점까지 연장할 수 있습니다.
- withExtendedLifetime의 몸체를 비워두어도 동일한 효과를 얻을 수 있습니다.
- 또는 보다 명시적으로 함수의 끝까지 객체를 유지하기 위해 defer문 안에서 사용할 수 있습니다.
- 하지만 이런 방법은 약한 참조가 버그를 일으킬 가능성이 있을 때마다 withExtendedLifetime을 적절히 배치해야 하므로 관리 비용이 증가합니다.
- 약한 참조에 대한 접근은 private으로 제한하고, 외부에서 접근해야 하는 경우에는 strong 참조를 통해서만 참조하면 문제를 피할 수 있습니다.
- 약한 참조는 생명주기에 의존하기 때문에, 아예 약한 참조를 사용하지 않는 것이 가장 좋은 방법입니다.
- 기존 구조를 수정하여 더 이상 순환 참조를 하지 않도록 디자인하면 모든 생명주기에 관련된 문제가 해결됩니다.
- deinit은 할당이 해제되기 직전에 호출됩니다.
- deinit에 side-effect가 있는 코드를 작성한 경우에는 객체의 수명이 변경될 때 발생하는 버그가 생길 수 있습니다.
- 예상되는 결과는 "Lily is deinitializing" 출력 후 "Done traveling"이 출력되는 것입니다.
- ARC 최적화에 따라서 "Done traveling" 출력 후 "Lily is deinitializing" 이 출력될 수 있습니다.
- computeTravelInterest() 함수가 category를 계산하기 때문에, traveler의 소멸이 computeTravelInterest() 이후인 경우에는 category가 포함되어 전송될 것이라고 예측할 수 있습니다.
- 하지만 traveler객체의 마지막 사용이 computeTravelInterest()를 호출하기 전이기 때문에 category가 계산되지 않고 nil로 처리될 수 있습니다.
- 이러한 경우 withExtendedLifetime를 호출하여 명시적으로 traveler객체의 수명을 연장할 수 있습니다.
- 하지만 잘못된 객체 수명을 참조하는 코드가 있을 때마다 호출해주어야 하므로 관리 비용이 늘어납니다.
- travelMetrics 객체를 private으로 선언하여 외부에서 computeTravelInterest()를 호출하지 못하게 하는 방법이 있습니다.
- 이런 경우 항상 deinit내에서 publish() 호출 이전에 computeTravelInterest()를 호출하게 되므로 문제가 해결됩니다.
- 근본적인 해결 방법은 deinit에서 side effect가 있는 코드를 호출하지 않는 것입니다.
- side effect가 있는 코드는 deinit 외부에서 처리하고, deinit에서는 수행에 대한 검증만을 수행하여 문제를 해결할 수 있습니다.
- Xcode 13에서는 Optimize Object Lifetimes라는 실험적인 빌드 설정을 할 수 있습니다.
- 이 빌드 설정을 활성화하면 객체가 수명이 좀 더 마지막 사용 직후에 일관되게 끝나는 것을 볼 수 있습니다.
- 이러한 옵션의 사용은 숨겨진 객체의 수명과 관련된 버그를 드러나게 해 줍니다.
'WWDC > WWDC 2021' 카테고리의 다른 글
WWDC 2021 - Detect and diagnose memory issues (0) | 2021.07.06 |
---|---|
WWDC 2021 - What’s new in AVFoundation (0) | 2021.07.05 |
WWDC 2021 - Understand and eliminate hangs from your app (0) | 2021.07.03 |
WWDC 2021 - What‘s new in Swift (0) | 2021.07.03 |
WWDC 2021 - Meet Xcode Cloud (0) | 2021.07.02 |
Comments