Фоновая тема iPad NSAutoReleasePool путаница о [выпуск объекта] - PullRequest
1 голос
/ 05 сентября 2010

У меня есть приложение, в которое я импортирую кучу данных, и я хочу, чтобы это происходило в фоновом потоке. Это работало хорошо для небольшого количества данных, но теперь кажется, что я сталкиваюсь с этой ошибкой на полпути при анализе и импорте больших объемов моих данных в Core Data:

Program received signal:  “EXC_BAD_ACCESS”.

Вот вызов фоновой темы:

[self performSelectorInBackground:@selector(importAllData) withObject:nil];

Вот пример того, что я делаю в своем коде:

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    // load manufactuers from DB
    NSFetchRequest *crequest    = [[NSFetchRequest alloc] init];
    NSEntityDescription *manufacturer = [NSEntityDescription entityForName:@"Manufacturer" inManagedObjectContext:managedObjectContext];
    [crequest setEntity:manufacturer];
    NSError *cerror=nil;;
    NSArray *manufacturers = [[managedObjectContext executeFetchRequest:crequest error:&cerror]mutableCopy];
    [crequest release];

for (int m=0; m < [manufacturers count]; m++) { 
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:kClientListURL, [[manufacturers objectAtIndex:m]ManufacturerID]]];

            ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
            [request setNumberOfTimesToRetryOnTimeout:2];
            [request startSynchronous];
            NSError *error = [request error];
            if (!error) {

                NSString *responseString = [request responseString];
                NSArray *items = [responseString JSONValue];

                NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
                NSNumberFormatter *dec  = [[NSNumberFormatter alloc]init];
                [dec setNumberStyle:NSNumberFormatterDecimalStyle];

                for (int i = 0; i < [items count]; i++) 
                {

                    Client *entity = (Client*) [NSEntityDescription insertNewObjectForEntityForName:@"Client" inManagedObjectContext:managedObjectContext];
                    [entity setCompanyName:[[items objectAtIndex:i] objectForKey:@"CompanyName"]];
                    // set a bunch of other properties
                    [entity setManufacturer:[manufacturers objectAtIndex:m]];

                    statusMessage = [NSString stringWithFormat:@"importing client: %@", entity.CompanyName];
                    [self performSelectorOnMainThread:@selector(setStatus) withObject:nil waitUntilDone:YES];
                }

                [f release];
                [dec release];

            } else {
                NSLog(@"%@",[NSString stringWithFormat:@"JSON parsing failed: %@", [error localizedDescription]]);
            }

            NSError *entityerror;
            if (![managedObjectContext save:&entityerror]) {
                //  //Handle the error.
                NSLog(@"\n\n\n Error saving clients: %@ \n\n\n\n",entityerror);
            }
    }
    //More data importing code

    [pool release];

Как я уже сказал, это работало нормально для небольшого количества данных, но теперь в симуляторе он выдает ошибочные ошибки доступа в случайных точках.

Тогда я прочитал эту статью, которая смутила меня: http://www.cocoadev.com/index.pl?DebuggingAutorelease

Мне не нужно освобождать мои объекты, если они находятся внутри NSAutoReleasePool? Я заставляю их быть выпущенными дважды в некоторый момент?

Если я удаляю операторы release, я получаю потенциальные ошибки утечек при сборке с использованием Command-Shift-A?

Ответы [ 2 ]

1 голос
/ 05 сентября 2010

Правила таковы:

  • Если вы владелец, вам нужно либо позвонить [object release], либо [object autorelease].Последний будет делегировать вызов release для NSAutoReleasePool, когда пул очищается или освобождается.
  • Вы являетесь владельцем, если вы вызвали [object retain] или если вы получили объект через метод, который имеет либо allocили copy в его имени.
  • Если вы получили объект из метода, в имени которого нет ни alloc, ни copy, и вы не сохранили его, вы не должны вызывать release илиautorelease на нем (за исключением очень редкого случая, когда документация утверждает, что вы являетесь владельцем).

Так что да, если вы получилиавтоматически выпущенный объект, и вы вызываете release для него, вы переиздаваете его.Эффекты различны, но почти всегда приводят к сбою, обычно с EXC_BAD_ACCESS.Вы можете отладить это, установив переменную окружения NSZombieEnabled .Таким образом, всякий раз, когда объект освобождается, он заменяется манекеном, который знает, какой объект жил по этому адресу ранее, а затем может сказать вам, какой объект был освобожден.

Но, читая ваш код, я не делалВыясните любую сразу очевидную проблему, но я недостаточно хорошо знаю Базовые Данные (которые вы, похоже, используете).Другая возможность - это проблема с потоками / временем.Кроме того, вы сказали, что это не весь метод?Возможно, ошибка в недостающей части.

0 голосов
/ 17 марта 2011

Я предполагаю, что importAllData - это метод, который вы используете. Если это так, вы пропускаете: в конце разговора.

[self performSelectorInBackground:@selector(importAllData) withObject:nil];

должно быть

[self performSelectorInBackground:@selector(importAllData:) withObject:nil];

Надеюсь, это поможет!

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