2012-02-25 108 views
2

我一直在使用來自Raphael Cruzeiro的代碼PDF Annotator,並且發現了一些內存泄漏(ARC關閉,並且將停留以支持較舊的設備)。大部分補丁修補完畢後,我倒到了最後一對,他們讓我難倒了。因此,在名爲PDFDocument的課程中,他具有CGPDFPageRef,CGPDFDocument和自定義註釋類別@synthesize'd的屬性。我不得不用釋放他的dealloc方法,並刪除一些懸掛指針,這除了一個小問題之外運行良好:經過大約3個完整的retain-release循環,它的註釋對象在@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 

然後我跑了通過儀器發現殭屍對象,果然,儀器發現正在發送的信息在完全相同的@synthesize行解除分配的對象!

有沒有人有任何想法是怎麼回事,以及如何解決它?

+1

只有第一代iPhone與ARC不兼容,爲什麼不使用它? – 2012-02-25 21:08:18

+0

僅僅是我自己的偏好......結合ARC重構工具現在令我煩惱的事實。嘆息......我現在就轉換。 – CodaFi 2012-02-25 21:27:56

+1

你說它在「合成」期間墜毀了。實際上,它是在' - (Annotation *)註釋'或' - (void)setAnnotation:(Annotation *)'合成方法中崩潰。可能是伊娃已經被釋放的二傳手。 – mattjgalloway 2012-02-25 21:30:03

回答

8

這一點看起來非常錯誤的:

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

首先,你爲什麼要檢查零岬self.annotation_annotation。這是有效地做兩次相同的檢查。

其次,你使用直接訪問伊娃釋放_annotation,然後annotation的setter將被再次釋放_annotation和設置_annotation = nil。正如你所看到的,是要過放_annotation

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

:有效它這樣做。

另外,嚴重的是,只需使用ARC。 ARC(主要)編譯時間與運行的設備或操作系統版本無關。 iOS5以前不支持的唯一一點是自動糾錯弱指針。但是這真的不應該成爲一個問題,因爲無論如何Lion/iOS 5都是全新的。

+0

這是我試圖弄清楚dealloc是否在扼殺物體。我添加了字節明智&因爲只檢查屬性沒有工作......無論如何,我希望我可以將它轉換爲ARC並與之結合。 – CodaFi 2012-02-25 21:35:38

+2

Byte wise&?這是合乎邏輯的,你已經到了那裏。它檢查從' - (Annotation *)註釋'返回的值是否爲非零,'_annotation'是否爲非零。 ' - (Annotation *)annotation'只是一個'return _annotation'。你得到的照片。 – mattjgalloway 2012-02-25 21:36:56

+0

ARC很棒,但很好理解底下發生了什麼。這也是「按位」,正如mattjgalloway所說,你沒有使用它。 – 2012-07-12 17:55:24

相關問題