我的环境是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:]
的方法有关。
是否还需要其他清理步骤来防止这些泄漏(或在非泄漏情况下内存膨胀)?
答案 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,但将使用委托调用。