Arhn - архитектура программирования

Должны ли мы выпустить NSDate вручную?

Я объявил NSDate в моем заголовочном файле со следующей конфигурацией:

# TestController.h
@interface TestController : UITableViewController{
    NSDate      *selectedDate;
    NSManagedObject *task;
}
    @property (nonatomic, retain) NSManagedObject *managedObject;
    @property (retain) NSDate *selectedDate 
@end

# TestController.m
@implementation TestController
    - (void)viewDidLoad {
        self.selectedDate = [managedObject valueForKey:@"title"];
    }
    - (void)viewDidUnload {
        self.task = nil;
        self.selectedDate = nil;
    }

    - (void)dealloc {
        [self.task release]
      [self.selectedDate release];
      [super dealloc];
    }
@end

Насколько я понимаю, вы должны освободить переменные, которые выделяются, копируются или сохраняются. Поскольку я сохраняю здесь переменные данные, я освобождаю их при освобождении. Но в конечном итоге возникает ошибка освобождения памяти:

"[NSDate isNSDate]: сообщение отправлено освобожденному экземпляру 0x6923750"

Если бы я не выпустил его вручную, он работал нормально. Мой вопрос: следует ли мне выпустить переменную для этого сценария?

Обновление:

Сделал инструментальный тест с шаблонами зомби, и вот результат:

#   Category    Event Type  RefCt   Timestamp   Address Size    Responsible Library Responsible Caller
0   __NSDate    Malloc  1   1331055104  0x895e9d0   16  CoreData    -[NSSQLCore _prepareResultsFromResultSet:usingFetchPlan:withMatchingRows:]
1   __NSDate    Retain  2   1333056000  0x895e9d0   0   Task    -[TaskViewCell configureData:]
2   __NSDate    Retain  3   3045008128  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
3   __NSDate    Retain  4   3054921984  0x895e9d0   0   CoreData    -[NSSQLRow copy]
4   __NSDate    Release 3   3059244032  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
5   __NSDate    Release 2   3059607040  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
6   __NSDate    Retain  3   3715918848  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
7   __NSDate    Retain  4   3727657984  0x895e9d0   0   CoreData    -[NSSQLRow copy]
8   __NSDate    Release 3   3730131200  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
9   __NSDate    Release 2   3730286080  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
10  __NSDate    Retain  3   4250617856  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
11  __NSDate    Retain  4   4250759936  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
12  __NSDate    Release 3   4250761984  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
13  __NSDate    Retain  4   4260489984  0x895e9d0   0   CoreData    -[NSSQLRow copy]
14  __NSDate    Release 3   4263536896  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
15  __NSDate    Release 2   4263687168  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
16  __NSDate    Release 1   4656624128  0x895e9d0   0   Task    -[TaskEditController dealloc]
17  __NSDate    Retain  2   7570179840  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
18  __NSDate    Retain  3   7570360064  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
19  __NSDate    Release 2   7570361088  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
20  __NSDate    Retain  3   7577499136  0x895e9d0   0   CoreData    -[NSSQLRow copy]
21  __NSDate    Release 2   7602608128  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
22  __NSDate    Release 1   7602752256  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
23  __NSDate    Release 0   7971558144  0x895e9d0   0   Task    -[TaskEditController dealloc]
24  __NSDate    Zombie  -1  9697122048  0x895e9d0   0   Foundation  -[NSDateFormatter stringForObjectValue:]

Не совсем понял, что это значит. Но я предполагаю, что coredata выпускает NSDate даже с сохранением?

19.05.2011

Ответы:


1

Лучший способ устранить проблему с чрезмерным освобождением объекта - запустить инструменты (в XCode введите ⌘-I вместо ⌘-R) и выбрать шаблон «Зомби» - он покажет вам, где находится каждый объект сохраняются и освобождаются, и сообщают вам, когда ваш код отправляет сообщение уже выпущенному экземпляру.

В этом случае возможно, что несбалансированный выпуск скрывается где-то еще в вашем коде, и размещение выпуска в вашем методе dealloc обнаруживает проблему, которая находится в другом месте. В любом случае, прямой ответ на ваш вопрос: «да, вы должны освободить сохраненную вами переменную», а код, который вы разместили здесь, имеет правильное соотношение удержаний к выпускам (то есть один к одному), поэтому Я бы поискал другие места, где вы могли бы выпустить этот NSDate.

19.05.2011
  • Что ж, быстро проведем поиск по проекту и не найдем места, где будет выпущен объект даты. Я получал объект даты из ManageObject и тоже его выпускал. Это вызовет проблемы? Я обновил свой код, скоро попробую ваш метод. Спасибо 19.05.2011

  • 2

    Вызов [ self.selectedDate release ] уменьшит счетчик удержания объекта в self.selectedDate, однако self.selectedDate по-прежнему содержит ссылку на объект даты (теперь уже освобожденный).

    Вам следует сделать это:

    self.selectedDate = nil.

    Так как:

    self.selectedDate = nil

    удобный синтаксис для этого фактического кода:

    [ self setSelectedDate:nil ]

    Метод setSelectedDate: автоматически генерируется

    @synthesize selectedDate.

    Поскольку свойство объявлено retain, сгенерированный установщик выглядит так:

    -(void)setSelectedDate:(NSDate*)date
    {
        [ selectedDate release ] ; // refers to the generated selectedDate instance variable in this class
        selectedDate = [ date retain ] ;
    }
    

    Наконец, если вам не нужен атомарный доступ (который вам не нужен в большинстве случаев), используйте вместо этого это объявление nonatomic:

    @property ( nonatomic, retain ) NSDate * date
    
    19.05.2011
  • Спасибо за подробное объяснение. Я обновил свой вопрос, чтобы лучше проиллюстрировать мой код. Я установил свой объект даты равным нулю для очистки справки. Я тоже пробую ваше неатомное объявление, но пока безуспешно. 19.05.2011
  • кстати - viewDidUnload вызывается не всегда. Он будет вызываться только в ситуациях с нехваткой памяти, когда ваше представление выгружено. В любом случае, код в dealloc все равно следует изменить на self.selectedDate = nil 19.05.2011
  • В таком случае я бы попробовал инструменты, как предлагал Скотт Форбс. (Используйте инструмент Allocations - вы сможете увидеть всю историю сохранения / выпуска / автоматического выпуска / выделения для каждого NSDate в вашей программе. Проблема должна исчезнуть сразу. 19.05.2011
  • Попробовал. Я обновил сообщение с журналом, похоже, что coredata выпускает NSDate. 19.05.2011
  • (Я бы не стал подозревать Core Data, если вы не уверены на 100%.) Похоже, что [ TestController dealloc ] выполняется дважды. Этого никогда не должно быть. Вы чрезмерно выпускаете TestController, но прежде чем это может вызвать проблемы, вы столкнетесь с этой проблемой. Убедитесь, что ваш TestController сохраняет / выпускает 19.05.2011
  • Причина, по которой [TestController dealloc] вызывается дважды, заключается в том, что приложение вылетает только тогда, когда я несколько раз прохожу между RootViewController и TestController. Я проверил, [релиз TestController] вызвал только один раз. Хм .. странно. 19.05.2011
  • Вы звонили в dealloc напрямую куда-нибудь? 19.05.2011
  • Ага. Я вызвал dealloc из viewWillAppear из RootViewController, но я проверил его перед повторным выпуском. если (testController) {[выпуск testController]; testController = ноль; } 21.05.2011
  • Вы имеете в виду, что звонили release, а не dealloc, верно? Вы не должны звонить dealloc 22.05.2011

  • 3

    Да, вам следует освободить любую принадлежащую вам переменную (выделенную, скопированную или сохраненную). Однако правильный способ освободить вашу переменную NSDate в методе dealloc должен быть либо:

    [selectedDate release];
    selectedDate = nil;
    

    OR

    self.selectedDate = nil;
    

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

    19.05.2011
  • Установка указателя на nil не приведет к его освобождению, ссылка все еще существует. 19.05.2011
  • Это комментарий о первом или втором подходе? 19.05.2011
  • Хорошо, я понимаю свойство с сохранением: при использовании self со свойством вызовет его метод установки и сначала освободит старое значение, нет? Разве это не работает? - (void) setVarid) newValue {if (var! = NewValue) {[var release]; var = newValue; [сохранение нового значения]; }}? 19.05.2011
  • проголосовать. использование self.selectedDate = nil правильно. Это эквивалентно [self setSelectedDate: nil]. Сгенерированный установщик (setSelectedDate:) освободит существующий объект после установки, поскольку свойство объявлено retain 19.05.2011
  • @Imran Прошу прощения, вы правы, сеттер по умолчанию освободит старую память, я неправильно понял, что вы написали. Я снял свой голос против. 19.05.2011

  • 4

    Пытаться

    [selectedDate release];
    

    Вместо

    [self.selectedDate release];
    
    19.05.2011
  • Нет. Ошибка, вызванная переменными, выпускалась раньше, но я выпускаю только метод dealloc класса. 19.05.2011
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..