NSViewController - 解除内存清理

时间:2016-02-24 15:05:41

标签: objective-c macos memory-leaks 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

根据Instruments,泄漏与名为[NSViewController _addPresentedViewController:]的方法有关。

是否还需要其他清理步骤来防止这些泄漏(或在非泄漏情况下内存膨胀)?

1 个答案:

答案 0 :(得分:0)

呈现另一个视图控制器的视图控制器也负责解除它。因此,FirstReplacement的dismiss方法中没有一行是正确的。相反,您应该在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,但将使用委托调用。