ARC 似乎正在释放我的 NSViewController 的视图

Posted

技术标签:

【中文标题】ARC 似乎正在释放我的 NSViewController 的视图【英文标题】:ARC seems to be releasing the view of my NSViewController 【发布时间】:2012-07-28 11:16:49 【问题描述】:

我正在尝试解决一个更大的问题,并且我认为 ARC 显然过早地向我的 NSViewController 发布了视图。我认为 :) 所以我创建了一个简单的应用程序来重建这种情况。

我有一个简单的 ARC Cocoa 应用程序。在MainMenu.xib 的窗口中,我将Custom View 连接到@property (strong) IBOutlet NSView *theView;,它在AppDelegate.h 中声明

AppDelegate.m我合成属性然后调用如下:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification

    TestViewController *tvc =  [[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
    [_theView addSubview:[tvc view]];
  

TestViewController 显示在 Custom View 中 - 没问题。它包含一个 NSButton。它连接到一个名为 -(IBAction)btnPressed:(id)sender 的方法和一个也连接为 IBOutlet 的 NSTextView。

TestViewController.h我声明:

@property (nonatomic, strong) IBOutlet NSTextField *textField;
@property (nonatomic, strong) NSString *theString;

-(IBAction)btnPressed:(id)sender;

TestViewController.m我然后做

@synthesize theString = _theString;
@synthesize textField = _textField;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Initialization code here.
        _theString = @"Hello World";
    

    return self;


-(IBAction)btnPressed:(id)sender

    [_textField setStringValue:_theString];

当我运行应用程序并按下按钮时,它会崩溃。如果我检查它是否有僵尸,我会收到以下信息:

#   Address Category    Event Type  RefCt   Timestamp   Size    Responsible Library Responsible Caller
0   0x7f97a3047560  TestViewController  Malloc  1   00:00.652.631   128 TestARC -[AppDelegate applicationDidFinishLaunching:]
1   0x7f97a3047560  TestViewController  Retain  2   00:00.653.088   0   TestARC -[TestViewController initWithNibName:bundle:]
2   0x7f97a3047560  TestViewController  Release 1   00:00.653.089   0   TestARC -[TestViewController initWithNibName:bundle:]
3   0x7f97a3047560  TestViewController  Retain  2   00:00.653.912   0   AppKit  -[NSNib instantiateNibWithOwner:topLevelObjects:]
4   0x7f97a3047560  TestViewController  Release 1   00:00.658.831   0   AppKit  -[NSNib instantiateNibWithOwner:topLevelObjects:]
5   0x7f97a3047560  TestViewController  Release 0   00:00.662.377   0   Foundation  -[NSNotificationCenter postNotificationName:object:userInfo:]
6   0x7f97a3047560  TestViewController  Zombie  -1  00:01.951.377   0   AppKit  -[NSApplication sendAction:to:from:]

我做错了什么? 谢谢

【问题讨论】:

【参考方案1】:

添加一个属性来保存视图控制器。在分配它的方法结束后,您的控制器目前没有任何东西可以使其保持活动状态。

添加:

@property (strong) TestViewController *tvc;

修改:

self.tvc =  [[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil];

(我很好奇......如果你想要的只是它包含的视图,你认为创建视图控制器的意义是什么?)


关于一般方法,这似乎是更恰当的行为,应该使用容器视图控制器来实现。该机制允许多个视图控制器以有组织的方式共享屏幕。

【讨论】:

我正在使用 ViewControllers 将不同的视图(及其各自的方法)加载到主窗口中的自定义视图中。我想将自定义视图用作可互换内容的“框架”。将 AppDelegate.h 更改为 @property (strong) IBOutlet TestViewController *theView; 会迫使我删除 addSubview,对吗?但这不会将 TestViewController 的视图加载到自定义视图中...... 不,如果这是您希望设计工作的方式,请留下 addSubview。正如我所说,subviews 数组将负责保留它。只有控制器的生命周期才是您原始编码中的问题。 (不过,获得我认为你想要的东西的更好支持的方法是创建一个容器视图控制器。使用这种结构,有定义的方法来维护父/子控制器关系。) 如果我保留 addSubview 行。然后我得到一个错误No visible @interface for 'TestViewController' declares the selector 'addSubview'. 对不起...我对您如何使用您定义的属性做出了错误的假设。与其更改作为属性的内容,不如为控制器添加一个新属性,并在创建时将其分配给该属性。我会更新我的答案。 我对我的一般方法还有另一个问题:在我的应用程序中,我有两个“部分”。每个部分彼此分开,但麻烦的是彼此相邻显示。这就是为什么我在主窗口上放置了两个自定义视图并将它们分别连接到两个 ViewController 的视图。我想在逻辑上和“物理上”分离代码。这是实现我想要做的事情的“错误”方式吗?【参考方案2】:

您需要添加一个 ivar 或属性来保存 TextViewController。目前,对它的唯一引用是在 applicationDidFinishLaunching: 的末尾消失,这会导致它被释放。

这很糟糕,因为您的按钮需要控制器在附近才能处理按钮按下。视图不会保留它的控制器,因为这会导致保留周期。因此,如果您不希望按钮与已释放的对象通信,则您有责任保持控制器在身边。

【讨论】:

以上是关于ARC 似乎正在释放我的 NSViewController 的视图的主要内容,如果未能解决你的问题,请参考以下文章

UIViewController 在 dealloc 时不释放子视图(使用 ARC)

强制对象在 ARC 下释放

移除对象时内存未释放 - 不清楚在 ARC 中释放的正确方法

为啥 ARC 在 popViewController 之后不释放内存

iOS:释放正在使用的对象 (ARC)

使用具有通用 setter 和 ARC 的 Objective-C 动态属性