почему мой UIViewController сохраняется дополнительное время при использовании initWithNibName?

#iphone #objective-c #memory-leaks

#iPhone #objective-c #утечки памяти

Вопрос:

Я работаю над приложением, в котором есть основной вид, который хочет создавать дочерний вид при нажатии кнопки. Поэтому, когда я получаю событие button, MainViewController запускает дочернее представление, вызывая initWithNibName и сохраняя childViewController в ivar . Затем я показываю дочернее представление, прикрепляя анимацию и устанавливая childVC.view.hidden = NO .

Это работает, но я заметил, что childViewController так и не был выпущен после закрытия childView. Я понял, что количество сохранений childVC увеличилось с 1 до 2 при первом доступе к дочернему представлению. Таким образом, что-то в процессе загрузки nib, похоже, снова сохраняет мой дочерний элементvc (в дополнение к первоначальному сохранению, которое я ожидаю во время инициализации объекта).

Может кто-нибудь помочь мне выяснить, почему дочерний файл сохраняется дополнительное время, и как я могу убедиться, что он полностью освобождается, когда я хочу закрыть дочернее представление?

Редактировать: вот некоторый код, только немного упрощенный. Это методы родительского контроллера представления.

 -(IBAction)onLaunchChildButtonTouched:(id)sender
{
    m_childViewController = [[ChildViewController alloc] initWithNibName:@"ChildViewController" bundle:nil];
    [m_childViewController setParentDelegate:self];  // this is a weak reference

    // m_childViewController retain count here is 1, as expected
    m_childViewController.view.hidden = YES;
    // m_childViewController retain count is now 2, not expected

    [self.view addSubview:m_childViewController.view];

    [self addTransitionEntrDir:YES];  // code omitted

    m_childViewController.view.hidden = NO;

}


-(void)onChildWantsToClose:(id)child
{
    NSAssert( child == m_childViewController, @"unexpected childVC" );

    // if child view is now hidden, we should remove it.
    if( m_childViewController != nil amp;amp; m_childViewController.view.hidden )
    {
        [m_childViewController.view removeFromSuperview];
        [m_childViewController release]; m_childViewController = nil;

        // BUG: m_childViewController retain count is still 1 here, so it never gets released

    }
}
  

Комментарии:

1. может быть, показать ваш фактический код?

2. Показ некоторого кода поможет привести к этому Q.

3. обновлено исходное сообщение с некоторым кодом.

Ответ №1:

Без кода трудно сказать точно, но вы уверены, что не присваиваете ChildVC retain свойству какого-либо другого объекта? Это объясняет неожиданное retain , что вы видите.

Извините за предыдущий ответ, где я пытался передать это же сообщение, но я все перепутал.

СТАРЫЙ ОТВЕТ:
имейте в виду, что view свойство a UIViewController сохраняется:
view

Представление, которым управляет контроллер.

@property(неатомный, сохранить) UIView * просмотр
итак, если вы назначаете ему так:
childVC.view = [[xxxxx alloc] initWithNibName:…];
это объясняет, что вы видите.
Используйте вместо этого:
childVC.view = [[[xxxxx alloc] initWithNibName:…] авторелиз];

Комментарии:

1. Спасибо за ваш ответ. Я использую initWithNibName для инициализации ViewController, а не view . Затем (согласно документам) свойство View автоматически загружается из кончика при первом доступе к нему. Я не выполняю автоматическое освобождение ViewController, но я вручную освобождаю его, когда дочернее представление закрыто. Проблема, похоже, в том, что дочерний файл сохраняется дополнительное время, и я не могу понять, почему.

Ответ №2:

Я обнаружил проблему, дырявый childViewController создавал экземпляр объекта, который сохранял ссылку на него.

Интересно то, что я не просто забыл выпустить эту ссылку. У меня был вызов для его освобождения, но этот код никогда не выполнялся, потому что предполагалось, что viewDidUnload запустится и даст мне шанс освободить все, но этого не произошло. Вместо этого я поместил свой код deinit в dealloc, и теперь он работает.

Комментарии:

1. Обычная область, в которой это происходит, — это когда вы addObserverForName:object:queue:usingBlock: NSNotificationCenter внутри viewDidLoad , со ссылками на self , но только removeObserver внутри dealloc . Dealloc никогда не будет вызываться по определению, потому что блок будет сохранен self . Вы можете сделать слабую ссылку на self , чтобы помочь обойти эту проблему, Или подписаться / отказаться от подписки на уведомления в viewWillAppear и viewDidDisappear и т. Д.