NSViewController - уволить с очисткой памяти

Моя среда - Yosemite 10.10.5 с Xcode 7.2, использующим ARC.

В простой тестовой программе я пытаюсь различными способами отклонить NSViewController и все они показывают проблемы с обработкой памяти.

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

- (IBAction)showFirstReplacement:(id)sender {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissWithNotification:) name:@"removeFirst" object:nil];
    NSStoryboard *sb = [self storyboard];
    FirstReplacement *controller = [sb instantiateControllerWithIdentifier:@"first_replacement"];
    [self presentViewControllerAsSheet:controller];
}

- (void)dismissWithNotification:(NSNotification *)notification {
    NSViewController *controller = [notification object];
    [self dismissViewController:controller];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

внутри FirstReplacement, Я имею:

- (IBAction)dismiss:(id)sender {
    [self dismissViewController:self];
//  [[NSNotificationCenter defaultCenter] postNotificationName:@"removeFirst" object:self];
//  [[self presentingViewController] dismissViewController:self];
}

Раскомментирование любой из трех строк в этом методе дает правильные визуальные результаты, но.... В зависимости от того, какие из вызовов я включаю внутри dismiss:Я получаю разные результаты при профилировании. С помощью self dismissViewController:Я не вижу утечек, но FirstReplacement объекты не освобождаются. Использование любого из двух других подходов избавляет от уволенных FirstReplacement но протекает один 16-байтовый блок malloc и один NSMutableArray каждый раз, когда контроллер представления отклоняется.

Согласно инструментам, утечки связаны с методом, называемым [NSViewController _addPresentedViewController:],

Есть ли другие меры по очистке, необходимые для предотвращения этих утечек (или раздувания памяти в случае отсутствия утечек)?

1 ответ

Контроллер представления, который представляет другой контроллер представления, также ответственен за отклонение этого. Таким образом, ни одна из строк в методе dismiss в FirstReplacement не является правильной. Вместо этого вы должны создать делегата в FirstReplacement, чтобы он мог уведомить своего делегата (основной контроллер представления) о том, что он должен быть отклонен.

FirstReplacement.h

@class FirstReplacement;

@protocol FirstReplacementDelegate <NSObject>
- (void)firstReplacementShouldDismiss:(FirstReplacement *)controller;
@end

@interface FirstReplacement : NSViewController
@property (nonatomic, weak) id<FirstReplacementDelegate> delegate;
@end

FirstReplacement.m

- (IBAction)dismiss:(id)sender {
    [self.delegate firstReplacementShouldDismiss:self];
}

Тогда в вашем основном контроллере представления:

- (IBAction)showFirstReplacement:(id)sender {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissWithNotification:) name:@"removeFirst" object:nil];
    NSStoryboard *sb = [self storyboard];
    FirstReplacement *controller = [sb instantiateControllerWithIdentifier:@"first_replacement"];
    controller.delegate = self;
    [self presentViewControllerAsSheet:controller];
}

- (void)firstReplacementShouldDismiss:(FirstReplacement *)controller {
    [self dismissViewController:controller];
}

Хотя может показаться, что отправка уведомления такая же, как и у делегата, это не так. Разница в том, что при запуске dismissWithNotification вы все равно выполняете код из FirstReplacement::dismiss. NSNotificationCenter::postNotificationName не завершает выполнение, пока все наблюдатели не завершат выполнение своих селекторов. Таким образом, даже несмотря на то, что код отклонения выполняется в основном контроллере представления, он все еще выполняется из метода dismiss.

Если вы все еще не уверены, переопределите FirstReplacement::dealloc, чтобы напечатать оператор журнала. Вы увидите, что dealloc не вызывается ни одним из ваших методов, но будет вызываться с помощью делегирования.

Другие вопросы по тегам