Разработка для iOS: почему счетчики сохранения для моего контроллера представления так странны? - PullRequest
4 голосов
/ 03 декабря 2010

Я погружаюсь в разработку под iOS и создаю приложение на основе навигации, которое не полностью высвободило одно из представлений, которое было перенесено в стек навигации.Это проблематично, поскольку контроллер представления никогда не освобождается, поэтому используемая им память просто накапливается каждый раз, когда контроллер представления помещается в стек.Поэтому после изучения проблемы я обнаружил, что количество сохраненных данных для контроллера представления было действительно странным.Рассматриваемый контроллер представления помещается в стек, как только таймер обратного отсчета достигает нуля.

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

-(void)updateCountDownTimer   //Defined in MyViewController_A class
{
    [self setTimeRemaining:([self timeRemaining] - 1)];

    [[self countDownLabel] setAlpha:1];
    [[self countDownLabel] setText:[NSString stringWithFormat:@"%d", [self timeRemaining]]];

    //Fade out the current time
    [UIView beginAnimations:@"FadeAnimation" context:nil];
    [UIView setAnimationDuration:1];
    [[self countDownLabel] setAlpha:0];
    [UIView commitAnimations];  

    if ([self timeRemaining] == 0) 
    {       
        MyViewController_B *myvc_b = [[MyViewController_B alloc] initWithNibName:@"MyView_B_iPhone" bundle:nil];
        [[self navigationController] pushViewController:myvc_b animated:YES];
        NSLog(@"updateCountDownTimer: %d", [myvc_b retainCount]);
        [myvc_b release];

        [[self countDownTimer] invalidate];
        [[self countDownLabel] setHidden:YES];
    }
}

и вот код, который выводит контроллер представления из стека навигации после нажатия кнопки паузы ...

- (void)pauseButtonPressed:(id)sender
{
    //Stop the timer
    [puzzleTimer invalidate];

    NSLog(@"pauseButtonPressed before pop: %d", [self retainCount]);

    //return to the previous view
    [[self navigationController] popViewControllerAnimated:YES];

    NSLog(@"pauseButtonPressed after pop: %d", [self retainCount]);
}

и вот вывод консоли, который действительно показываетстранные значения удержания в течение всего процесса ...

2010-12-02 17:50:38.062 MyApp[821:307] updateCountDownTimer: 5
2010-12-02 17:50:40.453 MyApp[821:307] pauseButtonPressed before pop: 2
2010-12-02 17:50:40.462 MyApp[821:307] pauseButtonPressed after pop: 4

Я новичок в разработке для iOS, но код кажется мне довольно простым, поэтому я не знаю, что мне не хватает.

Большое спасибо за вашу мудрость!

ОБНОВЛЕНИЕ : Похоже, что инструмент Leaks сообщает об утечке в строке кодаэто помещает предыдущий контроллер представления в стек (то есть контроллер представления, ответственный за передачу рассматриваемого контроллера представления).Код снова очень прост, поэтому я не знаю, почему он сообщает об утечке ...

MyViewController_A *myvc_a = [[MyViewController_A alloc] initWithNibName:@"MyView_A_iPhone" bundle:nil];

[[self navigationController] pushViewController:myvc_a animated:YES]; //<--Leak being reported here

[myvc_a release];

* ОБНОВЛЕНИЕ: * Обнаружил проблему, это было так же, как всеБыло сказано, и та же проблема, что была показана в ссылке, размещенной в комментариях ниже, у меня были живые объекты, все еще ссылающиеся на мой контроллер вида, что препятствовало его освобождению.В моем случае у меня было два таймера, которые предназначались для моего контроллера представления, и те таймеры не были аннулированы до того, как я вытолкнул представление из стека, что означало, что два живых объекта все еще ссылаются на контроллер представления.Вот фрагмент кода, который я нашел в документации Apple, которая раскрыла проблему ...

Возможно, что еще важнее, таймер также поддерживает четкую ссылку на свою цель.Это означает, что до тех пор, пока таймер остается в силе (и в противном случае вы должным образом соблюдаете правила управления памятью), его цель не будет освобождена.

В любом случае, еще раз спасибо всем, кто помог!

Ответы [ 3 ]

3 голосов
/ 03 декабря 2010

Вы ничего не упускаете - экземпляры UINavigationController просто делают странные, странные вещи для внутреннего подсчета.

Вам следует беспокоиться о retainCount, только если вы видите конкретную утечку памятичто ты пытаешься исправить.В этом случае, конечно, у вас действительно есть проблема ... retainCount просто не помогает, поскольку это так странно.

Вы можете проверить, вызывается ли dealloc на MyViewController, когда высделать поп.Кроме того, перед тестированием закомментируйте строки, которые проверяют retainCount.Вызов retainCount иногда добавляет к retainCount.

Чтобы действительно понять, что происходит, в Xcode перейдите в меню «Выполнить» и выберите «Выполнить с помощью Performance Tool»> «Утечки».Нажмите и вытолкните тот контроллер представления, и вы должны увидеть его как утечку.Вы сможете увидеть все вызовы retain и release на объекте.

Если вы действительно застряли, руководство Apple по Поиск утечек содержит еще несколькоумные решения.Удачи!

2 голосов
/ 03 декабря 2010

Что касается управления памятью, в вашем коде нет ничего плохого.

Вы не должны полагаться на счет удержания, чтобы проверить, правильно ли высвобождаются ваши объекты, поскольку система также сохранит то, что ей нужно, и освободит при необходимости. Например, когда вы добавляете свой контроллер представления в стек, он сохраняется контроллером nav вместе со своими подпредставлениями, а когда он выдвигается, он отправляет сообщение об освобождении, которое распространяет все его подпредставления.

Общее правило: если вы размещаете, сохраняете или копируете объект, вы обязаны его освободить. Все остальное обрабатывается системой и будет сброшено с помощью пула автоматического выпуска.

1 голос
/ 03 декабря 2010

Никогда, никогда, никогда не смотрите на количество сохраняемых объектов.Они не должны использоваться программно и вводят в заблуждение, когда вы пытаетесь отладить свой код.

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

Дело в том, что вы никогда не должны смотреть на счет сохранения ваших объектов по любой причине в любое время.Они будут только сбивать вас с толку.Ваша работа состоит в том, чтобы правильно управлять вашими требованиями к объекту и верить, что код, написанный другими, делает то же самое.

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