Должен ли я сохранять объект автоматического освобождения при назначении сохраненному свойству? - PullRequest
1 голос
/ 21 февраля 2011

В получателе для одного из моих сохраненных свойств я выделяю и присваиваю NSArray для моего объекта модели («модели»). Затем я сортирую этот NSArray, используя метод "sortedArrayUsingSelector:". Согласно документам, это возвращает автоматически выпущенный NSArray обратно. Затем я переназначаю это моему массиву "models".

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

У меня такой вопрос: правильно ли, что мне нужно сохранять автоматически выпущенный объект, даже если я сохраняю это свойство в его объявлении и освобождаю его в моем dealloc?

- (NSArray *)models {

    if (!models) {
        models = [[NSArray alloc] initWithArray:[self.modelDictionary allKeys]];
        models = [[models sortedArrayUsingSelector:@selector(compare:)] retain];
    }
    return models;

}

Ответы [ 3 ]

7 голосов
/ 21 февраля 2011

В общем, если вы хотите, чтобы объект с автоматически выпущенным объектом оставался вокруг, вы должны retain его.

Есть несколько проблем с этим кодом:

- (NSArray *)models {

    if (!models) {
        models = [[NSArray alloc] initWithArray:[self.modelDictionary allKeys]];
        models = [[models sortedArrayUsingSelector:@selector(compare:)] retain];
    }
    return models;
}
  • вы пропускаете массив, равный alloc/init d со второй models= строкой кода

  • , которую вы сказали «сохраняя это свойство в своем объявлении, но в приведенном вышекод, который вы присваиваете переменной экземпляра напрямую, минуя метод установки, который может быть сгенерирован @synthesize

  • , это метод получения, который изменяет состояние получаемой переменной.... хотя этот тип ленивой инициализации может быть привлекательным, его следует выполнять с особой тщательностью. Базовые данные идут очень долго - из-за некоторой внутренней сложности - чтобы обеспечить ленивое заполнение состояния таким способом.Код также будет означать, что наблюдатели значения ключа свойства models не увидят изменения при выполнении метода получения, но если вы вызовете willChangeValueForKey:/didChangeValueForKey: вручную из метода получения, вы получитеотправка уведомления об изменении из getter, вполне вероятно, что что-то будет использовать значение до того, как тот, кто вызвал метод получения, сначала получит значение.Звук сбивает с толку?Это - это может или не может вызвать проблемы.По моему опыту, это может вызвать проблемы в один прекрасный день.

Некоторые предложения:

  • используйте Базовые данные, если можете.По-настоящему огромный объем инженерных работ был затрачен на то, чтобы сделать основные данные очень эффективными и очень хорошо интегрированными в систему.

  • отделяет геттер / сеттер от остальной логики.Скорее всего, в вашем приложении есть логическая точка, в которой вам нужно «достать» модели.Когда вы это сделаете, сообщите объекту об ошибке в каком-либо другом методе , затем получите модели.Это может показаться болезненным, но построение графа объектов - это скорее специализированная задача, чем запрос этого графа для получения информации (или использование базовых данных, для которых есть решение).

1 голос
/ 21 февраля 2011

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

self.models =  [NSArray arrayWithArray:[self.modelDictionary allKeys]];

Без части self. вы не используете метод установки и, следовательно, никогда ничего не сохраняете.

0 голосов
/ 21 февраля 2011

Спасибо!Я понимаю что ты имеешь в виду.Я думаю, что запутался и подумал, что вызов self.models в моем геттере создаст бесконечный цикл.Теперь я вижу, что это просто, если я вызываю получатель изнутри, а не установщик изнутри.Я изменил свой код на это:

- (NSArray *)models {
    if (!models) {
        self.models = [[NSArray alloc] initWithArray:[self.modelDictionary allKeys]];
        self.models = [models sortedArrayUsingSelector:@selector(compare:)];
    }
    return models;
}

все компилируется и работает нормально ... это выглядит как более правильное решение?Спасибо за ваше время.

...