2010-09-08 5 views
0

По какой-то причине, когда я выпускаю NSArray, я получаю исключение EXC_BAD_ACCESS. Вот реализация:Управление памятью NSArray

-(void) loadAllAlphabets 
{ 
    NSBundle *bundle = [NSBundle mainBundle]; 
    NSArray *imagesPath = [[NSArray alloc] init]; 

    imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"]; 

    alphabets = [[NSMutableArray alloc] init]; 

    NSString *fileName = [[NSString alloc] init]; 

    for(int i=0; i<= imagesPath.count -1 ; i++) 
    { 
     fileName = [[imagesPath objectAtIndex:i] lastPathComponent]; 
     CCSprite *sprite = [CCSprite spriteWithFile:fileName]; 

     sprite.userData = [[fileName stringByDeletingPathExtension] uppercaseString]; 

     [alphabets addObject:sprite]; 
    } 

    // release fileName 
    [fileName release]; 
    fileName = nil; 

    [imagesPath release]; // this causes the application to crash with EXC_BAD_ACCESS 
// imagesPath = nil; 

}

UPDATE 1:

Итак, проблема заключалась в том, что, хотя я был ответственен за освобождение объекта imagesPath, поскольку я использовал Alloc, что скоро станет неуместным, когда pathsForResourcesOfType возвратил объект автоопределения. Это означает, что я не должен освобождать объект imagesPath вручную.

В следующей строке следует использовать:

NSArray *imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"]; 

UPDATE 2:

Другой вопрос, который связан с этой должности. В следующем коде я инициализирую новый NSMutableArray вручную.

alphabets = [[NSMutableArray alloc] init]; 

Позже я вставляю CCSprite (объекты Cocos2d) в массив алфавитов. CCSprite являются объектами автореферата. Должен ли я все же выпускать алфавиты вручную? Так как через какое-то время все объекты будут выпущены, и память будет возвращена, но тогда что останется в алфавитах NSMutable массива?

+0

Утечка происходит, когда вы переназначаете imagesPath на путиForResourcesOfType: call, потому что вы уже выделили и я –

ответ

4

Общее правило большого пальца в управлении памятью - вы должны освободить объект, только если вы его получите с помощью метода, который содержит новый, копировать или выделять в нем (стандартный метод следует этому правилу, и вы также должны придерживаться его).

В вашем случае вы получаете объект imagesPath с использованием метода pathsForResourcesOfType:, который возвращает объект с автореализацией, поэтому вы не должны его выпускать самостоятельно.

Редактировать: Да, вам необходимо освободить объект alphabets (по той же причине - вы получили его с помощью метода alloc).

Контейнеры Objective-c приобретают права собственности на объекты, добавленные к ним, когда мы добавляем объекты в массив, который они сохраняют, поэтому гарантируется, что срок их жизни не меньше, чем срок службы контейнера. Когда вы удаляете объект из коллекции или самой коллекции, уничтожается, тогда ее члены освобождаются (чтобы компенсировать сохранение при добавлении).

+0

Спасибо Владимиру! Итак, хотя я выделил imagesPath, pathsForResourcesOfType возвратил объект autorelease, который я не должен выпускать вручную. – azamsharp

6

Я думаю, что путаница здесь:

NSArray *imagesPath = [[NSArray alloc] init]; 
imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"]; 

Первая строка создает новый объект. Этот объект действительно должен быть выпущен.

Вторая строка переписывает этот объект с новым самообслуживаемым объектом. Это не необходимо вручную освободить.

Это означает, что вы пропускаете первые изображения.

В целом, вам необходимо освободить объект, если вы его alloc или copy. И вы не должны переписывать объект до того, как вы опубликуете (или авторизуете) его содержимое.

3

Кроме того, вы пропускаете память при инициализации imagesPath с пустым не изменяемым массивом и затем отбрасываете его, когда назначаете ему результат pathsForResources:. Просто сделайте это вместо:

NSArray *imagesPath = [bundle pathsForResourcesOfType:@"png" inDirectory:@"Images"]; 

та же ошибка с fileName. Не нужно инициализировать его пустой пустой переменной.

А также не выпускать fileName, так как это также автореализованный объект.

+0

Причина fileName - объект autorelease, потому что он исходит из imagesPath NSArray правильно? – azamsharp

+0

Кроме того, если я запускаю цикл и назначая fileName, это означает, что я создаю новый объект NSString для каждого цикла. – azamsharp

+0

@azamsharp yes, значение из строки 'fileName = [[NSString alloc] init];' отбрасывается, когда вы назначаете ему автореализованную строку внутри цикла. Лично я инициализировал fileName с помощью nil перед циклом – Vladimir

Смежные вопросы