Сообщение отправлено для нераспределенного экземпляра ... Отправлено во время @synthesize? - PullRequest
2 голосов
/ 26 февраля 2012

Я использовал код из PDF Annotator от Raphael Cruzeiro и обнаружил ряд утечек памяти (ARC выключен и будет отключен для поддержки старых устройств).После исправления большинства из них, я до последней пары, и они поставили меня в тупик.Таким образом, в классе с именем PDFDocument у него есть свойства для CGPDFPageRef, CGPDFDocument и пользовательский класс аннотаций @synthesize 'd.Мне пришлось добавить его метод dealloc к релизам и устранить некоторые висячие указатели, которые хорошо работают, за исключением одной небольшой проблемы: после примерно 3 полных циклов сохранения-выпуска он падает на строке @synthesize для его объекта аннотации ...никогда не видел SIGABRT из-за освобожденного объекта, отправленного во время @synthesize, поэтому, естественно, понятия не имею, как это исправить.Если я удаляю код релиза в 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 Ответ

8 голосов
/ 26 февраля 2012

Этот бит выглядит очень неправильно:

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

Во-первых, почему вы проверяете self.annotation и _annotation на ноль.Это фактически делает одну и ту же проверку дважды.

Во-вторых, вы используете прямой доступ ivar к релизу _annotation, и тогда установщик для annotation снова выпустит _annotation и установит _annotation = nil.Фактически он делает это:

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

Который, как вы видите, собирается перевыпустить _annotation.

Кроме того, серьезно, просто используйте ARC.ARC (в основном) является временем компиляции и не имеет никакого отношения к устройству или версии ОС, на которой он работает.Единственный бит, который не поддерживается в предварительной версии iOS 5 - это автоматические нулевые слабые указатели.Но это действительно не должно быть проблемой, так как это все-таки совершенно новое в Lion / iOS 5.

...