Chapter 20
메모리 누수 막기
양방향의 관계 갖기 : 자식의 포인터를 다시 그 부모를 가리키도록 추가
Asset.h
#import <Foundation/Foundation.h> @class Employee; @interface Asset : NSObject { NSString *label; Employee *holder; unsignedint resaleValue; } @property (strong) NSString *label; @property (strong) Employee *holder; @propertyunsignedint resaleValue; @end |
Asset.m
#import "Asset.h" #import "Employee.h" @implementation Asset @synthesize label, resaleValue, holder; -(NSString *)description { if([self holder]) { return [NSStringstringWithFormat:@"<%@: $%d , assigned to %@>", [selflabel], [selfresaleValue], [selfholder]]; } else { return [NSStringstringWithFormat:@"<%@: $%d unassigned>", [selflabel], [selfresaleValue]]; } } -(void)dealloc { NSLog(@"deallocating %@", self); } @end |
두 관계가 일관된 것인지 확인하는 방법
비품이 직원의 비품 배열에서 나타날 경우는 오직 그 직원이 그 비품의 보유자
두 관계의 명시적 설정
[vicePresident addAssetsObject:townCar]; [townCar setHolder:vicePresident]; |
자식의 포인터를 설정하는 메소드에서 자식을 부모의 컬렉션에 추가
-(void) setHolder : (Employee *)e { holder = e; [e addAssetsObject:self]; } |
자식을 부모의 컬렉션에 추가하는 메소드에서 자식의 포인터를 설정
-(void)addAssetsObject: (Asset *) a { // assets가닐인가? if (!assets) { // 배열을만든다. assets = [[NSMutableArray alloc] init]; } [assets addObject:a]; [a setHolder:self]; } |
AddAssetsObject:메서드 확장
→ 그래도 메모리에서 취소가 되지 않음
[유지 사이클]
객체가 메모리에서 취소되어야 메모리 공간이 넒어지는데 그러지 못한 현상
메모리 누수의 원인
solution : Instruments를 이용해 프로파일한다.
프로파일한다
: 프로그램이 실행되는 동안 이면에서 무슨일이 일어나는지 면밀히 지켜본다. 보통 프로파일할 시간을 벌기위해 main()함수 끝에 sleep(초)을 추가한다.
[약한 참조]
유지사이클을 해결하는 방법
소유권을 주장하지 않는 포인터
상속관계에서 유지사이클을 막는 법?
: 부모는 자식을 소유해도 자식은 부모를 소유할 수 없도록 설정
#import <Foundation/Foundation.h> @class Employee; @interface Asset : NSObject { NSString *label; __weak Employee *holder; unsignedint resaleValue; } @property (strong) NSString *label; @property(weak) Employee *holder; @propertyunsignedint resaleValue; @end |
holder의 약한참조
[약한참조를 0으로 만들기]
약한 참조가 가리키는 객체가 취소되면 그 포인터 변수는 0이 되었다고 말한다.
→ nill로 설정
[조금 더 깊게 - 참조 수동 카운팅과 ARC]
참조수동카운팅
유지카운트를 사용하는 방식
객체가 메시지를 명시적으로 받아 유지카운트를 줄이거나 늘릴때만 소유권 변경이 일어난다.
[anObject release]; [anObject retain]; |
위와 같은 형태는 엑세서 메소드, dealloc 메서드에서 볼 수 있다.
-(void) setHolder:(Employee *)newEmp { [newEmp retain]; [holder release]; holder = newEmp; } |
엑세서 메서드 : 새로운 값이 유지되고 이전 값은 정리
-(void)dealloc { [labelrelease]; [holder release]; [superdealloc]; } |
Dealloc메서드 : 이전에 유지됐던 모든 객체가 정리
-(NSString *)description { NSString *result = [[NSSTringalloc] initWithFormat:@"<%@: $%d >", [selflabel], [selfresaleValue]]; [result autorelease]; return result; } |
Description 메서드 : 문자열을 만들어 리턴
release는 자동정리 풀이 비워질 때 받는다.
NSAutoreleasePool *arp = [[NSAutoleasePoolalloc] init]; Asset *asset = [[Assetalloc] init]]; NSString *d = [assetdescription]; [arp drain]; |
[유지 카운트 규칙]
alloc, new로 시작, copy가 들어가는 메소드를 사용해서 객체를 만들면 소유권을 갖게 된다.(소유권을 넘겨주는 메소드 – alloc, copy, mutableCopy)
retain 메세지를 통해 객체를 소유하지 않지만 존재 상태를 보장
객체를 소유하는데 더 이살 필요치 않을 때 release, autorelease메시지 사용
release : 유지 카운트를 즉시 줄인다.
autorelease : 자동 정리 풀이 비워질 때
객체의 소유자가 존재하는 동안 객체는 계속 존재
댓글