2012-02-25 2 views
2

저는 Raphael Cruzeiro의 PDF Annotator 코드를 사용하여 ARC가 꺼져 있고 오래된 장치를 지원하기 위해 많은 메모리 누수가 있음을 발견했습니다. 대부분을 패치 한 후, 나는 지난 커플에게로 내려 갔고, 그들은 나를 곤혹스럽게 만들었다. 따라서 PDFDocument 클래스에서 그는 CGPDFPageRef, CGPDFDocument 및 맞춤 주석 클래스 @synthesize 'd에 대한 속성을가집니다. 나는 그의 dealloc 메소드를 릴리즈로 후 처리해야만하고 하나의 작은 문제를 제외하고는 잘 작동하는 매달려있는 포인터를 제거해야했다 : 약 3 개의 완전한 유지 해제 사이클 후에, @ annhesation 객체의 @synthesize 라인에서 충돌이 발생했다. @synthesize 중에 전송 된 할당 해제 된 객체 때문에 SIGABRT를 본 적이 없으므로 자연스럽게 어떻게 수정해야하는지 모릅니다. dealloc에서 릴리스 코드를 제거하면 누수가 발생하지만이를 그대로두면 충돌이 발생합니다. 여기에 PDFDocument 클래스의 코드가있다 : 좀비 오브젝트를 찾을 수 할당 해제 된 인스턴스로 보낸 메시지 ... @synthesize 중 보낸 메시지?

//.h 

#import <Foundation/Foundation.h> 

@class Annotation; 

@interface PDFDocument : NSObject { 
    Annotation *_annotation; 
} 

- (id)initWithDocument:(NSString *)documentPath; 

- (NSInteger) pageCount; 
- (void) loadPage:(NSInteger)number; 
- (BOOL)save; 

@property (nonatomic, retain) NSString *name; 
@property (nonatomic, retain) NSString *hash; 
@property (readwrite, nonatomic, assign) CGPDFDocumentRef document; 
@property (readwrite, nonatomic, assign) CGPDFPageRef page; 

@property (nonatomic, retain) NSString *version; 

@property (nonatomic, assign) BOOL dirty; 

@property (nonatomic, retain) Annotation *annotation; 

@end 

//.m 
#import "PDFDocument.h" 
#import "Annotation.h" 
#import "HashExtensions.h" 
#import "DocumentDeserializer.h" 
#import "DocumentSerializer.h" 


@implementation PDFDocument 

@synthesize document; 
@synthesize page; 
@synthesize annotation = _annotation; //after 3rd cycle, it crashes here. 
@synthesize name; 
@synthesize hash; 
@synthesize dirty; 
@synthesize version; 

- (id)initWithDocument:(NSString *)documentPath 
{ 
    if((self = [super init]) != NULL) { 

     self.name = [documentPath lastPathComponent]; 
     if ([self.name isEqualToString:@"Musette.pdf"] || [self.name isEqualToString:@"Minore.pdf"] || [self.name isEqualToString:@"Cantata.pdf"] || [self.name isEqualToString:@"Finalé.pdf"]) 
     { 
     CFURLRef ref = CFBundleCopyResourceURL(CFBundleGetMainBundle(), (CFStringRef)self.name, NULL, NULL); 
     self.document = CGPDFDocumentCreateWithURL(ref); 
     self.page = CGPDFDocumentGetPage(document, 1); 
     self.version = @"1.0"; 
     DocumentDeserializer *deserializer = [[[DocumentDeserializer alloc] init] autorelease]; 
     self.annotation = [deserializer readAnnotation:[[(NSURL*)ref absoluteString] stringByDeletingPathExtension]]; 

     CFRelease(ref); 
     } 

     else { 

      CFURLRef pdfURL = (CFURLRef)[[NSURL alloc] initFileURLWithPath:documentPath]; 
      self.document = CGPDFDocumentCreateWithURL(pdfURL); 
      self.page = CGPDFDocumentGetPage(document, 1); 
      self.version = @"1.0"; 
      DocumentDeserializer *deserializer = [[[DocumentDeserializer alloc] init] autorelease]; 
      self.annotation = [deserializer readAnnotation:[[(NSURL*)pdfURL absoluteString] stringByDeletingPathExtension]]; 

      CFRelease(pdfURL); 
      CGPDFPageRelease(self.page); 

     } 
    } 

    return self; 
} 

- (NSInteger)pageCount 
{ 
    return CGPDFDocumentGetNumberOfPages(self.document); 
} 

- (void)loadPage:(NSInteger)number 
{ 
    self.page = CGPDFDocumentGetPage(document, number); 
} 

- (BOOL)save 
{ 
    DocumentSerializer *serializer = [[[DocumentSerializer alloc] init] autorelease]; 
    [serializer serialize:self]; 

    self.dirty = NO; 
    return !self.dirty; 
} 

- (void)dealloc 
{ 
    CGPDFDocumentRelease(self.document); 
    if (self.annotation != nil && _annotation != nil) { 
     [_annotation release]; 
     self.annotation = nil; 
    } //my attempt to prevent the object from being over-released 
    self.document = nil; 
    self.name = nil; 
    [super dealloc]; 
} 

@end 

가 그럼 난 악기를 통해 실행하고, 확실히 충분히, Instruments는 할당이 해제 된 객체가 동일한 @synthesize 라인에 메시지를 보내는 발견!

누구에게 무슨 일이 벌어지고 있고 어떻게 수정해야하는지 알 수 있습니까?

+1

1 세대 iPhone 만 ARC와 호환되지 않습니다. 왜 사용하지 않습니까? –

+0

단지 내 자신의 환경 설정 ... ARC 리팩토링 도구가 지금 당황 스럽다는 사실과 결합되었습니다. 한숨 ... 나는 지금 개종 할거야. – CodaFi

+1

"합성 중"오류가 발생했다고합니다. 실제로, 그것은'- (Annotation *) annotation' 또는'- (void) setAnnotation : (Annotation *)'합성 메소드 중 하나에서 충돌하는 것입니다. 이미 ivar가 벌써 석방 된 세터 일거야. – mattjgalloway

답변

8

은이 비트는 매우 잘못된 같습니다

if (self.annotation != nil && _annotation != nil) { 
    [_annotation release]; 
    self.annotation = nil; 
} 

을 첫째로, 당신은 왜 무풍 다움에 대한 self.annotation_annotation을 확인하고 있습니다. 그것은 효과적으로 같은 수표를 두 번하고 있습니다.

둘째, 당신은 _annotation을 해제 직접 바르 액세스를 사용하고 다음 annotation에 대한 세터 다시 _annotation을 해제하고 _annotation = nil 설정됩니다. 효과적으로이 일 것 :

if (self.annotation != nil && _annotation != nil) { 
    [_annotation release]; 
    [_annotation release]; 
    _annotation = [nil retain]; 
} 

당신이 볼 수 있듯이, _annotation을 지나치게 출시 할 예정이다.

또한 심각하게 말해서 ARC 만 사용하십시오. ARC는 (주로) 컴파일 시간이며 실행중인 장치 또는 OS 버전과 아무 관련이 없습니다. 중고 iOS 5에서 지원되지 않는 유일한 비트는 자동 제외 약 포인터입니다. 어쨌든 라이온/iOS 5에서 완전히 새로운 점은 사실 문제가 아닙니다.

+0

그것은 dealloc이 객체를 채우고 있는지를 알아내는 내 시도였습니다. 속성을 검사하는 것이 효과가 없었기 때문에 바이트 현명한 &를 추가했습니다 ... 어느 쪽이든 나는 단지 ARC로 변환하고 끝낼 수 있습니다. – CodaFi

+2

바이트 현명한 &? 그건 논리적이고 당신이 거기에있어. '- (Annotation *) annotation'에서 반환 된 값이 nil이 아니고'_annotation'이 nil이 아닌지 확인하고 있습니다. '- (Annotation *) annotation'은'return _annotation' 일뿐입니다. 너는 그림을 얻는다. – mattjgalloway

+0

ARC는 훌륭하지만 어쨌든 무슨 일이 일어나고 있는지 이해하는 것이 좋습니다. 또한 "bitwise"이고, mattjgalloway가 말했듯이, 당신은 그것을 사용하지 않고 있습니다. –