티스토리 뷰
ARC에서의 메모리관리 - Cocoa(+Touch) Framework의 메모리 관리(2)
hanweeee 2021. 3. 15. 19:52소유권 수식어
Objective-C
다음과 같은 수식어를 사용 할 수 있다.
__strong
- 강한참조, 해당 수식어를 가진 포인터로 객체를 참조하게되면 retain count가 1증가한다.
__weak
- 약한참조, 해당 수식어를 가진 포인터로 객체를 참조하여도 retain count가 증가하지않는다.
__unsafe_unretained
- 약한참조, 해당 수식으를 가진 포인터로 객체를 참조하여도 retain count가 증가하지않는다.
__autoreleasing
- 오토릴리즈를 할 객체의 수식어로 붙혀준다.
예제
__strong
id __strong obj1 = [[NSObject alloc] init];
id __strong obj2 = obj1;
NSLog(@"log1:%@",obj1);
NSLog(@"log2:%@",obj2);
obj1 = nil;
NSLog(@"log3:%@",obj1);
NSLog(@"log4:%@",obj2);
__strong 결과
2021-03-14 14:54:52.735758+0900 ARC_MemorySample_Ojbc[40372:360247] log1:<NSObject: 0x600002ddc9f0>
2021-03-14 14:54:52.735855+0900 ARC_MemorySample_Ojbc[40372:360247] log2:<NSObject: 0x600002ddc9f0>
2021-03-14 14:54:52.735926+0900 ARC_MemorySample_Ojbc[40372:360247] log3:(null)
2021-03-14 14:54:52.736001+0900 ARC_MemorySample_Ojbc[40372:360247] log4:<NSObject: 0x600002ddc9f0>
__weak
id __strong obj1 = [[NSObject alloc] init];
id __weak obj2 = obj1;
NSLog(@"log1:%@",obj1);
NSLog(@"log2:%@",obj2);
obj1 = nil;
NSLog(@"log3:%@",obj1);
NSLog(@"log4:%@",obj2);
__weak 결과
2021-03-14 14:54:52.735758+0900 ARC_MemorySample_Ojbc[40372:360247] log1:<NSObject: 0x600002ddc9f0>
2021-03-14 14:54:52.735855+0900 ARC_MemorySample_Ojbc[40372:360247] log2:<NSObject: 0x600002ddc9f0>
2021-03-14 14:54:52.735926+0900 ARC_MemorySample_Ojbc[40372:360247] log3:(null)
2021-03-14 14:54:52.736001+0900 ARC_MemorySample_Ojbc[40372:360247] log4:(null)
__weak와 __unsafe_unretained가 다른점은?
__unsafe_unretained 예제
id __strong obj1 = [[NSObject alloc] init];
id __unsafe_unretained obj2 = obj1;
NSLog(@"log1:%@",obj1);
NSLog(@"log2:%@",obj2);
obj1 = nil;
NSLog(@"log3:%@",obj1);
NSLog(@"log4:%@",obj2);
__unsafe_unretained 결과
결과를 보면 알겠지만 __weak의 경우엔 가리키고 있는 객체가 메모리에서 날라가면 nil로 set되지만 __unsafe_unretained는 여전히 해당 객체가 있던 주소를 바라보고있다.
프로퍼티에서 사용할 경우
프로퍼티에서 해당 수식어를 사용하고싶다면 다음과 같이 매칭시켜 사용하면 된다.
프로퍼티 수식어 | 소유권 수식어 |
assign | __unsafe_unretained |
copy | __strong(새로 복사된 객체가 할당된다.) |
retain | __strong |
strong | __strong |
unsafe_unretained | __unsafe_unretained |
weak | __weak |
예제
@property (weak) NSData *myData;
@property (strong) NSDate *myData2;
autorelese
__autoreleasing? 굳이 쓸 필요 없다. 왜? 의미가 없기때문.. 아래예제를 참고
예제
@autoreleasepool {
id __strong obj1 = [[NSObject alloc] init];
NSLog(@"log1:%@",obj1);
/* 오토릴리즈풀 안에 있기때문에 obj1은 오토릴리즈 풀에 등록이 된다. */
}
/* @autoreleasepool 블록을 벗어났기때문에 풀에 등록이 되어있는 객체는 자동릴리즈된다. */
Swift
다음과 같은 수식어를 사용 할 수 있다.
strong
- 강한참조, 해당 수식어를 가진 변수로 객체를 참조하게되면 retain count가 1증가한다.
weak
- 약한참조, 해당 수식어를 가진 변수로 객체를 참조하여도 retain count가 증가하지않는다.
unowned
- 약한참조, 해당 수식으를 가진 변수로 객체를 참조하여도 retain count가 증가하지않는다.
예제
strong
var myObj: NSObject? = NSObject()
let myObjPtr: NSObject? = myObj
print("log1:\(myObj)")
print("log2:\(myObjPtr)")
myObj = nil
print("log3:\(myObj)")
print("log4:\(myObjPtr)")
strong 결과
log1:Optional(<NSObject: 0x6000036481d0>)
log2:Optional(<NSObject: 0x6000036481d0>)
log3:nil
log4:Optional(<NSObject: 0x6000036481d0>)
weak
var myObj: NSObject? = NSObject()
weak var myObjPtr: NSObject? = myObj
print("log1:\(myObj)")
print("log2:\(myObjPtr)")
myObj = nil
print("log3:\(myObj)")
print("log4:\(myObjPtr)")
weak 결과
log1:Optional(<NSObject: 0x6000036481d0>)
log2:Optional(<NSObject: 0x6000036481d0>)
log3:nil
log4:nil
weak VS unowned
Objective-C의 __weak와 __unsafe_unratained의 차이와 정확히 동일하다. (위 참조)
weak를 사용해 순환참조 탈출하기
순환참조?
객체간의 포인터가 서로가 서로를 가르키게 되면 메모리 누수가 발생한다.
class ParentsClass {
var child: ChildrenClass?
init() {
}
func makeChild() {
self.child = ChildrenClass(parentsClass: self)
}
}
class ChildrenClass {
var parentsClass: ParentsClass
init(parentsClass: ParentsClass) {
self.parentsClass = parentsClass
}
}
class ViewController: UIViewController {
func circulationReference() { //순환참조가 발생한다.
let myClass = ParentsClass()
myClass.makeChild()
}
}
parentsClass가 강한참조로 child를 가지고있고, ChildrentClass역시 강한참조로 parantsClass를 가지고있다. 즉, 서로가 서로를 강한참조로 가르키고 있으니 retain count가 줄어 들 수 없다.
weak 수식어로 한곳의 포인터를 retain count를 증가시키지 않게 만들어서 탈출하자 !
class ParentsClass {
var child: ChildrenClass?
init() {
}
func makeChild() {
self.child = ChildrenClass(parentsClass: self)
}
}
class ChildrenClass {
weak var parentsClass: ParentsClass? //weak 수식어를 사용함으로써 부모클래스의 retain count를 늘리지 않는다.
init(parentsClass: ParentsClass) {
self.parentsClass = parentsClass
}
}
class ViewController: UIViewController {
func circulationReference() { //순환참조가 발생하지않는다.
let myClass = ParentsClass() myClass.makeChild()
}
}
HanweeeeLee/TestModules
이것저것 테스트하는 레포지토리입니다. Contribute to HanweeeeLee/TestModules development by creating an account on GitHub.
github.com
참조: iOS와 OS X의 메모리 관리와 멀티스레딩 기법 - 가즈키 사카모토, 도모히코 후루모토
'프로그래밍 > Cocoa & Cocoa Touch Framework' 카테고리의 다른 글
MRC에서의 메모리동작 - Cocoa(+Touch) Framework의 메모리 관리(1) (0) | 2021.03.15 |
---|
- Total
- Today
- Yesterday
- Objective-C
- ios
- Fastlane
- swift
- modulemap
- SwiftUI
- Delegate
- iOS Mnemonic
- Gitlab Runner
- 순환참조
- module map
- iOS 니모닉
- RxSwift
- associated type
- Protocol
- cicd
- XCodeGen
- arc
- flatMap
- widget extension
- firebase distribution
- Tuist
- CI
- cd
- XCode Cloud
- isSecureTextEntry
- Secure Enclave
- Swift 니모닉
- 니모닉
- iOS wallet
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |