2012-05-12 1 views
4

ivar 대신 속성을 릴리스했기 때문에 이것이 아니라면이 내용을 이해할 수 없습니다. 누군가 문제를 밝힐 수 있습니까?이 시점에서 소유하지 않은 참조 횟수의 감소가 올바르지 않습니다.

self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000]; 
    [self.dataToBeLoaded release]; 

경고는 Incorrect decrement of the reference count of an object that is not owned by the caller입니다.

dataToBeLoaded 속성에는 해당 설정자와 관련된 retain 특성이 있습니다.

제 생각에는 alloc init이 보유 수를 증가시키고 속성 할당이 보유 수를 증가시킵니다. 나는 단 한 번만 그것을 지니고 있기 때문에, 그 일은 임무를 마친 직후에 풀어 놓는 이유입니다.

UPDATE - 일부 실험 결과는 : 그 아래에있는 내 의견에 언급 때문에

나는이 건물은 합성 세터로 수행 보유 내용에 모순 조언을받은, 내가 사용하는 작은 실험을 할 것이라고 생각 일부 로깅을 수정 위의 코드, 각 로그 문에서

NSLog(@"retain 1 = %d", [dataToBeLoaded_ retainCount]); 
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000]; 
NSLog(@"retain 2 = %d", [dataToBeLoaded_ retainCount]); 
[self.dataToBeLoaded release]; 
NSLog(@"retain 3 = %d", [dataToBeLoaded_ retainCount]); 

결과는 0 2이었고, 1

분명히, 그것은 개입하는 것은 불가능합니다 alloc 또는 0으로 1에서 2로 유지 카운트를 볼 초기화 코드. NSMutableData 클래스를 서브 클래 싱 할 수 있지만 시간이 부족했다.

retainCount 속성의 값에 의존 할 수 없다는 것을 많이 알고 있지만 일관성이있는 것처럼 보이고 예제에 표시된 것과 같은 코드의 짧은 범위에 대해 합당한 동작을 기대합니다. 그래서 저는 사전 충고가 정확하다고 믿을 것입니다 - 보유 재산은 세터 내에 보유를 포함하는 약속입니다. 그래서 여기에 alloc/init의 유지와 setter 호출의 유지가 있습니다. 나는이 코드를 실행하면 따라서 유지 수는 2

으로 설정됩니다

NSMutableData *theData; 
NSLog(@"retain 1 = %d", [theData retainCount]); 
theData= [[NSMutableData alloc] initWithLength:10000]; 
NSLog(@"retain 1a = %d", [theData retainCount]); 
self.dataToBeLoaded = theData; 
NSLog(@"retain 2 = %d", [theData retainCount]); 
[self.dataToBeLoaded release]; 
NSLog(@"retain 3 = %d", [theData retainCount]); 

는 각 로그 문에서 수를 유지를 그래서

1. 내가 가진, 2, 1, 0 세터가 retain을 제공하고 있음을 나타내는 증거. 이것은 실제로 일어나기 때문에 암시보다 더 많은 약속처럼 보입니다.

다른 설명이 열려 있습니다. 나는 이것에 대해 오만하지 않기를 바란다. 나는 다만 일어나고있는 무슨을에 관해서는 권리를 얻고 싶다. 나는 경고 (이 질문의 주제에)가 정말로 가짜이며 걱정할 것이 없다고 생각한다.

@property 문에서 속성으로 retain이 아닌 assign을 사용하면 한 번 더 실험을 수행 할 수 있습니다. 동일한 코드 : message sent to deallocated instance :

NSMutableData *theData; 
NSLog(@"retain 1 = %d", [theData retainCount]); 
theData= [[NSMutableData alloc] initWithLength:10000]; 
NSLog(@"retain 1a = %d", [theData retainCount]); 
self.dataToBeLoaded = theData; 
NSLog(@"retain 2 = %d", [theData retainCount]); 
[self.dataToBeLoaded release]; 
NSLog(@"retain 3 = %d", [theData retainCount]); 

(가) 각 로그에 카운트를 유지하여 0, 1, 1 (세터가 유지되지 않았다), 그 에러 메시지이다. 마지막 릴리스에서는 보유 수를 0으로 설정하여 할당 해제를 트리거했습니다.

UPDATE 2

마지막 업데이트 - 세터가 명시 적으로 포함하지 않는 합성 세터가 자신의 코드로 대체되면, 유지 속성은 더 이상 관찰되지 않는다. 분명히 (그리고 이것은 내가 여기에있는 다른 스레드에서 말한 것과 모순이됩니다.) 당신이 원한다면 세터에 자신의 소유권을 포함시켜야합니다. 여기서 테스트하지는 않았지만 이전 인스턴스를 먼저 릴리스해야합니다. 그렇지 않으면 누출됩니다.

이 지정 세터는 더 이상 @propety 선언의 등록 정보 속성이 없습니다 :

- (void) setDataToBeLoaded:(NSMutableData *)dataToBeLoaded { 
    dataToBeLoaded_ = dataToBeLoaded; 
} 

이 의미가 있습니다. 합성 된 setter를 재정의하고 선언 된 모든 속성을 무시합니다. 합성 된 setter를 사용하면 선언 된 속성이 합성 된 구현에서 관찰됩니다.

@property 속성은 합성 된 setter가 구현되는 방법에 대한 "약속"을 나타냅니다. 일단 사용자 정의 setter를 작성하면 스스로 해결할 수 있습니다.

답변

0

나는 여기에서 무슨 일이 벌어지고있는가에 대한 답변을 몇 가지 제공했다. 일부 테스트 결과에서이 결론은 부적절한 코드를 식별하지 못한다는 것을 의미합니다. 업데이트는 스스로에 대해 말해야합니다. 그들은 위에 주어진 것입니다.

1

소유하고 있지 않은 개체를 출시한다는 의미입니다.

나는 getter를 사용하는 대신 직접 인스턴스 var를 사용하여 호출하는 것이 좋지만 분석 경고를 수정할지 여부는 확실하지 않습니다. 또한 [NSMutableData dataWithLength : 1000]을 사용하지 않는 이유는 무엇입니까? 이는 오토 릴리즈 따라서 여분의 릴리스 전화의 필요성을 제거 (! 아마도 너무 그 경고를 제거 것)되어

다른 방법을 당신이 그것을 고칠 수 :

NSMutableData *data = [[NSMutableData alloc] initWithLength:1000]; 
self.databToBeLoaded = data; 
[data release]; 
2

내 생각 엔이 방법 있다는 것

- (NSMutableData *)dataToBeLoaded; 

는 데이터가 반환 소유 따라서는 그렇지 할 것으로 가정 메모리 관리 키워드를 포함하지 않으며, 따라서 해제 할 수 없습니다.

어느

NSMutableData *data = [[NSMutableData alloc] initWithLength:1000]; 
self.dataToBeLoaded = data; 
[data release]; data = nil; 

를 사용하거나 할 수 있다면 왜 게으른 부하 그것은 당신이 실제로 필요?

- (NSMutableData *)dataToBeLoaded; 
{ 
    if (!_dataToBeLoaded) { 
     _dataToBeLoaded = [[NSMutableData alloc] initWithLength:1000]; 
    } 
    return _dataToBeLoaded; 
} 
4

핵심은 아래 코드가 무엇을하는지 생각하는 것입니다. 나는 명확성을 위해 전체에 그것을 밖으로 쓸 것이다 :

[self setDataToBeLoaded:[[NSMutableData alloc] initWithLength:10000]]; 

는이 수를 유지 +1로 객체를 생성하고 setDataToBeLoaded:에 전달합니다. (*) 그런 다음 객체에 대한 참조를 버리고 누설합니다.

[[self dataToBeLoaded] release]; 

dataToBeLoaded 호출 해제는 객체가 돌려. dataToBeLoaded에 의해 반환 된 객체가 setDataToBeLoaded:에 전달 된 객체와 동일하다는 약속은 전혀 없습니다. 아마 그들은 동일하다고 생각하고 자신의 코드를 살펴보면 항상 그렇게 할 것이라고 확신 할 수 있지만 API 약속은 아닙니다.Antwan 의해 등록한

코드 올 : +1 갖는 오브젝트를 작성

NSMutableData *data = [[NSMutableData alloc] initWithLength:1000]; 
self.dataToBeLoaded = data; 
[data release]; 

는 카운트를 유지한다. 그런 다음 메소드에 전달한 다음 메소드를 해제합니다.

또는, 당신은 오토 릴리즈 풀을 사용하고자하는 경우, 당신은 그것을 단순화 할 수 있습니다 :

self.dataToBeLoaded = [NSMutableData dataWithLength:1000]; 

(*) 기술적이 나이 발생하지 않을 수있다 self에 메시지를 전달합니다 메서드를 호출 할 수 있지만 그 문제를 muddies. 대부분의 경우, 메소드 호출이라고 가장합니다. 그러나 이 아니라 단지이 속성을 설정한다고 가장합니다. 실제로 어떤 방법을 호출 할 것입니다.


편집 :

어쩌면이 코드는 문제가 좀 명확하게됩니다. 그것은 일반적인 캐싱 솔루션을 나타내는입니다 :

.h 
@interface MYObject : NSObject 
@property (nonatomic, readwrite, strong) NSString *stuff; 
@end 

.m 
@interface MYObject() 
@property (nonatomic, readwrite, weak) MYStuffManager *manager; 

@implementation MYObject 

... Initialize manager ... 

- (NSString*)stuff { 
    return [self.manager stuffForObject:self]; 
} 

- (void)setStuff:(NSString *)stuff { 
    [self.manager setStuff:stuff forObject:self]; 
} 

지금 어쩌면 manager 백그라운드에서 일부 어리석은 짓을한다. 어쩌면 stuff의 다양한 사본을 캐시 할 수 있습니다. 어쩌면 그것들을 복사 할 수 있습니다. 어쩌면 그것들을 다른 물건으로 감쌀 것입니다. 중요한 것은 -stuff에 의존하여 항상 -setStuff:으로 전달 된 동일한 객체를 반환 할 수 없다는 것입니다. 그래서 당신은 확실히 그것을 공개해서는 안됩니다.

헤더에 아무 것도 표시되어 있지 않음을 유의하십시오. 발신자의 사업이 아닙니다. 그러나 발신자가 -stuff의 결과를 발표하면 디버그하기가 어려워집니다.

@synthesize은 좀 지루한 코드 작성 (읽기로 stuffsetStuff:을 구현하는 코드를하고 바르를 작성)을위한 속기이다. 그러나 아무것도 당신의 재산에 @synthesize 사용해야 만한다고합니다.

+0

저는 setter가 메소드 호출이라는 것을 알고 있습니다. 어쩌면 나는 속성이 보유 속성을 보유하고있는 경우 해당 설정자를 완전히 이해하지 못했을 수도 있습니다. 유지 된 속성에 대한 setter는 이전에 참조 된 인스턴스를 먼저 해제하고 (또는 말하자면 멀리 던집니다), 전달 된 인스턴스 참조를 할당 한 다음 유지합니다. 이제 전달 된 인스턴스는 이미 alloc/init에 의해 한 번 유지됩니다. - 그런데 참조 된 인스턴스가 0이되면 버려진 참조 된 인스턴스는이 프로세스에서 유출되지 않습니다. 당신의 설명에 뭔가 빠졌습니까? – Jim

+0

API 약속보다는 특정 구현에 대해 너무 많이 가정합니다. 당신은'setDataToBeLoaded :'가 ivar을 할당하고 그것을 유지한다고 가정하고 있습니다. 이것은 API가 약속하지 않은 것입니다. "보유"속성은 API의 약속이 아닙니다. 그것은 힌트이며, @synthesize에 의해 사용됩니다 (그러나 @synthesize는 API와 관련이 없습니다). 희망적으로 더 명확하게되기를 바란다 : 당신이 소유하지 않은 것을 절대로 공개하지 마십시오. 'dataToBeLoaded'를 호출해도 반환 값의 소유권을 갖지 않습니다. 메소드에 이름에 새/copy/alloc이 없습니다. 당신은 그것을 소유하지 않습니다. –

+0

누설이 없다고 말씀하셨습니다. 당신은 실제로 있습니다. 당신은 누설되고 당신은 과도하게 풀어 놓았고, 둘은 균형을 이루기 때문에 Instruments에서 누수가 보이지 않습니다.그러나 정적 분석기는 두 가지 모두에 유의해야합니다. –

관련 문제