2012-02-25 18 views
2

私はRaphael CruzeiroのPDF Annotatorのコードを使用していて、数多くのメモリリークを発見しました(ARCはオフになっており、古いデバイスをサポートするためには使用できません)。それらのほとんどをパッチした後、私は最後のカップルに行って、彼らは私を困惑させた。したがって、PDFDocumentというクラスでは、彼はCGPDFPageRef,CGPDFDocument、カスタムアノテーションクラス@synthesize 'dのプロパティを持っています。私は、リリースでdeallocメソッドをペーストしなければならなかったし、小さな問題を除いてうまくいくいくつかのぶら下がりポインタを排除しなければならなかった:約3つの完全な解放サイクルの後、@ annhesationオブジェクトの@synthesize行でクラッシュする... @synthesize中に送信された割り当て解除されたオブジェクトのためにSIGABRTを見たことはないので、自然にそれを修正する方法は知られていません。 deallocでリリースコードを削除した場合はリークしますが、残しておくとクラッシュします。ここでPDFDocumentクラスのコードだ:解放されたインスタンスに送信されたメッセージ... @合成中に送信されましたか?

//.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

第1世代のiPhoneのみがARCと互換性がありません。なぜあなたはそれを使用しませんか? –

+0

私の好みだけ... ARCリファクタリングツールが今私を迷惑にしているという事実と組み合わさっています。一言...私は今すぐ改宗するつもりです。 – CodaFi

+1

合成中にクラッシュしたとします。実際には、 - (Annotation *)注釈、または - (void)setAnnotation:(Annotation *)合成メソッドのいずれかでクラッシュすることです。おそらくイーゼルがすでにリリースされているセッターでしょう。 – mattjgalloway

答えて

8

このビットは、非常に間違っになります

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

を第一に、なぜあなたがnilネスのためのself.annotation_annotationをチェックしています。これは効果的に同じチェックを2回実行しています。

第二に、あなたは_annotationを解放するために直接IVARのアクセスを使用していて、その後、annotationのためのセッターは再び_annotationを解放し、_annotation = nilを設定します。効果的には、このやっている:あなたが見ることができるよう

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

を、過リリース_annotationに起こっています。

また、真剣に、ARCを使用してください。 ARCは(主に)コンパイル時に実行されているデバイスやOSのバージョンとは関係ありません。 pre iOS 5でサポートされていない唯一のビットは、自動ニルエイド弱ポインタ​​です。とにかくそれはLion/iOS 5でまったく新しくなっているので、本当に問題ではありません。

+0

これは、deallocがオブジェクトを埋めているかどうかを調べるための私の試みでした。私はバイトワイズを追加しました。なぜなら、プロパティだけをチェックするのはうまくいきませんでした...うまくいけば、私はそのものをARCに変換し、それを上書きすることができます。 – CodaFi

+2

バイトワイズ&?それはあなたがそこに持っている論理的なものです。 ' - (Annotation *)annotation'から返された値がnilでなく、' _annotation'がnilでないかどうかをチェックしています。 ' - (Annotation *)annotation'はちょうど' return _annotation'になります。あなたは写真を手に入れます。 – mattjgalloway

+0

ARCは素晴らしいですが、とにかく下に何が起こっているのかを理解することは良いことです。また、それは "bitwise"で、mattjgallowayが言ったように、あなたはそれを使用していません。 –

関連する問題