Почему освобождение моего массива приводит к сбою моего приложения? - PullRequest
1 голос
/ 14 ноября 2011

Если я освобождаю свой первый массив после того, как скопировал его во второй массив, мое приложение вылетает. Если я автоматически выпускаю первый массив, все работает нормально. Зачем? Есть ли лучший способ скопировать первый массив во второй массив?

Если я вызываю этот метод, я получаю ECX_BAD_ACCESS, я передаю пустой массив

-(NSArray *)loadSystemDetails
{
    AssortedCodeSnippets *acs = [[AssortedCodeSnippets alloc] init];
    NSArray *details;
    NSString *fp = [self tempPathAndFileName:[self systemDetailsFileName]];
    if ([acs fileExistsAtPath:fp]) {
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:fp];
        details = array;
        [array release];
    } else {
        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release];
        [self saveDataFile:details toPath:fp];
    }
    NSLog(@"details: %@",details);
    [acs release];
    return details;
}

Если я автоматически освобождаю массив, он работает нормально.

-(NSArray *)loadSystemDetails
{
    AssortedCodeSnippets *acs = [[AssortedCodeSnippets alloc] init];
    NSArray *details;
    NSString *fp = [self tempPathAndFileName:[self systemDetailsFileName]];
    if ([acs fileExistsAtPath:fp]) {
        NSArray *array = [[[NSArray alloc] initWithContentsOfFile:fp]autorelease];
        details = array;
    } else {
        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release];
        [self saveDataFile:details toPath:fp];
    }

Ответы [ 3 ]

2 голосов
/ 14 ноября 2011

Давайте пройдем через это

Ключ: M = сообщение об отпускании / сохранении, C = сумма сообщений об отпускании / сохранении

                                                              // +----+---+
                                                              // | M  | C |
                                                              // +----+---+
NSArray *array = [[NSArray alloc] initWithContentsOfFile:fp]; // | +1 | 1 |
details = array;                                              // |  0 | 1 |
[array release];                                              // | -1 | 0 |
                                                              // +----+---+

В этот момент вы можете видеть, что вы собираетесь возвращать details, счетчик которого равен 0, поэтому он уже был освобожден = крах.

Копия - неправильный термин, поскольку вам на самом деле не нужна копия, так как вы просто хотите, чтобы указатель details указывал на действительный объект, поэтому следующее будет более правильным

- (NSArray *)systemDetails
{
    NSString *filePath = [self tempPathAndFileName:[self systemDetailsFileName]];

    NSArray *details = [[[NSArray alloc] initWithContentsOfFile:filePath] autorelease];

    if (!details) {

        NSLog(@"No File to Load");
        CreateSystem *cls = [[CreateSystem alloc] init];
        details = [cls loadData];
        [cls release]; cls = nil;
        [self saveDataFile:details toPath:filePath];

    }

    NSLog(@"details: %@",details);

    return details;
}

Здесь я использую метод NSArray

initWithContentsOfFile:

... [возвращает] nil, если файл не может быть открыт или содержимое файла не может быть проанализировано в массив

Это сокращает некоторые из ошибок и делает метод более легким для чтения. Я также расширил имена переменных до значимых имен (личные предпочтения).

Я также переименовал метод, так как load искусство излишне, так как по сути вы возвращаете подробности системы, тот факт, что они загружаются, на самом деле не имеет значения для вызывающего метода.

Также важно отметить, что другие ответы предполагают, что вы берете дополнительное сохранение / копирование и затем не забудьте опубликовать возвращенный результат позже. Это противоречит соглашению по какао, так как имя метода не содержит new / init / copy, поэтому вызывающие методы не должны в конечном итоге владеть результатом.

1 голос
/ 14 ноября 2011

В вашем примере кода вы на самом деле не копируете array в details.Помните, что обе эти переменные являются указателями на массивы, а не на сами массивы.Таким образом, строка details = array просто копирует местоположение array в details.Другими словами, после этой строки обе переменные указывают на один и тот же массив в памяти.Следовательно, когда вы вызываете release, объект в памяти освобождается, и и details, и array теперь указывают на несуществующий объект.Если вы действительно хотите скопировать массив в память, используйте

details = [array copy]

Помните, что в конечном итоге вам придется вызывать release на details, когда вы хотите избавиться от этого объекта.

1 голос
/ 14 ноября 2011

Отправить details назначение сообщения retain, когда details указывает на array или результат cls '-loadData метода.Обязательно release details где-нибудь после -loadSystemDetails метода.

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