Пример приложения Какао, подсчет ссылок, [утечка пула] дает EXC_BAD_ACCESS? - PullRequest
2 голосов
/ 23 января 2009

Я работаю через Программирование Какао для Mac OS X (3-е издание) и в главе 4 я написал это приложение:

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    //create the date object
    NSCalendarDate *now = [[NSCalendarDate alloc] init];

    //seed random # generator
    srandom(time(NULL));

    NSMutableArray *array;
    array = [[NSMutableArray alloc] init];
    int i;
    for (i=0; i<10; i++){
        //create a date/time that is 'i' weeks from now
        NSCalendarDate *iWeeksFromNow;
        iWeeksFromNow = [now dateByAddingYears:0
                                        months:0
                                          days:(i*7)
                                         hours:0
                                       minutes:0
                                       seconds:0];

        //create a new instance of lottery entry
        LotteryEntry *entry = [[LotteryEntry alloc] init];
        [entry setEntryDate:iWeeksFromNow];

        [array addObject:entry];
        [entry release];
    }
    [now release];
    now = nil;

    for (LotteryEntry *entryToPrint in array) {
        NSLog(@"%@", entryToPrint);
    }
    [array release];
    array = nil;

    NSLog(@"about to drain the pool... (%@)", pool);
    [pool drain];
    NSLog(@"done");
    NSLog(@"GC = %@", [NSGarbageCollector defaultCollector]);
    return 0;
}

Класс LotteryEntry выглядит следующим образом:

@implementation LotteryEntry

- (void)setEntryDate:(NSCalendarDate *)date
{
    entryDate = date;
}

- (NSCalendarDate *)entryDate
{
    return entryDate;
}

- (int)firstNumber
{
    return firstNumber;
}

- (int)secondNumber
{
    return secondNumber;
}

- (id)init
{
    return [self initWithDate:[NSCalendarDate calendarDate]];
}

- (id)initWithDate:(NSCalendarDate *)date
{
    if(![super init])
        return nil;

    NSAssert(date != nil, @"Argument must be non-nil");

    firstNumber = random() % 100 + 1;
    secondNumber = random() % 100 + 1;
    entryDate = [date retain];  
    return self;
}

- (NSString *)description
{
    NSString *result;
    result = [[NSString alloc] initWithFormat:@"%@ = %d and %d",
              [entryDate descriptionWithCalendarFormat:@"%b %d %Y"],
              firstNumber,
              secondNumber];
    return result;
}

- (void)dealloc
{
    NSLog(@"deallocating %@", self);
    [entryDate release];
    [super dealloc];
}

@end

Как вы видите, я сохраняю и отпускаю объекты здесь. Я почти уверен, что мой код соответствует коду книги, однако, когда я запускаю приложение, в [сток бассейна] я получаю это сообщение:

Программа получила сигнал: «EXC_BAD_ACCESS».

Я не уверен, что вызвало это. Я надеюсь, что это что-то глупое, что я пропустил, но я бы оценил несколько других пар глаз на это. Заранее спасибо!

(примечание: я являюсь разработчиком .NET, поэтому подсчет ссылок довольно чужд для меня!)

Ответы [ 3 ]

3 голосов
/ 23 января 2009

Похоже, у вас есть ошибка в этом методе:

- (id)initWithDate:(NSCalendarDate *)date
{
    if(![super init])
        return nil;

    NSAssert(date != nil, @"Argument must be non-nil");

    firstNumber = random() % 100 + 1;
    secondNumber = random() % 100 + 1;
    entryDate = [date retain];  
    return self;
}

Вы, по сути, отбрасываете результаты [super init], хотя в этом случае это может не быть проблемой, это может вызвать серьезные проблемы в других. Вы должны 'всегда' структурировать методы инициализации, подобные этой:

- (id)initWithDate:(NSCalendarDate *)date
{
    if(self = [super init]) {
        NSAssert(date != nil, @"Argument must be non-nil");

        firstNumber = random() % 100 + 1;
        secondNumber = random() % 100 + 1;
        entryDate = [date retain];
}
return self;

Если вы не собираетесь возвращать себя из метода init (например, это фабрика или что-то странное в этом роде), вы должны не забыть освободить себя. Он был распределен, и если вы не вернете его, он не может быть освобожден должным образом. Пример:

- (id) init
{
    NSObject*    newSelf = [[NSObject alloc] init];

    [self release];
    return newSelf;
}
2 голосов
/ 23 января 2009

DOH! Просто набрав код, я понял свою проблему. Донче нравится, когда это происходит?

Я сохраняю дату в моем init, но у меня все еще был тот дополнительный setEntryDate метод, который не вызывал retain. Удаление этого и вызов метода initWithDate вместо этого, казалось, решили проблему.

1 голос
/ 23 января 2009

Это не связано с вашей проблемой, но вам следует избегать использования NSCalendarDate, оно уже давно устарело и, вероятно, будет удалено из API совсем скоро.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...