将自释放对象转换为ARC

时间:2012-02-22 11:14:57

标签: macos cocoa design-patterns memory-management automatic-ref-counting

好的,所以Apple给我们带来了ARC,这很棒。在将我的应用程序重构为AR​​C之后,几乎所有工作都很正常,现在开发和维护起来要容易得多。

我只能解决一个问题。

我的工作管理程序在自己的窗口中显示提案,订单等的不同详细信息。所以我有一个特殊的类,其中WindowControllers被分配并使用initWithWindowNibName启动,然后窗口显示为showWindow:

DetailWindowController *proposalWindowController = [[DetailWindowController alloc] initWithWindowNibName:@"ThePorposalWindow"];
[proposalWindowController showWindow:nil];

在ARC之前,WindowController的实例执行了documentation中所示的发布:

- (void)windowWillClose:(NSNotification *)notification
{
   [self autorelease];
}

但是现在使用ARC这是不可能的,更糟糕​​的是,在我分配和启动WindowController的特殊类中,ARC释放了相同的windowController,因为没有指向windowController的指针。

我的想法是将windowController复制到一个可变数组中:

[proposalWindowArray addObject:proposalWindowController];
[[proposalWindowArray lastObject] showWindow:nil];

在windowControllers委托方法windowWillClose中我将通知发布到我的特殊类:

- (void)windowWillClose:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ProposalWindowWillClose" object:[[self window] windowController] userInfo:nil];
}

在我的特殊课程中,我听取通知并从数组中删除对象:

- (void) proposalWindowWasClosed: (NSNotification *) notification
{
    [proposalWindowArray removeObjectIdenticalTo:[notification object]];
}

它有效,但我仍然不相信这是正确的方法。

是否有人有同样的问题或提示让它变得更好?

4 个答案:

答案 0 :(得分:10)

我可能会使用委托方法而不是通知。通常,最好有一个跟踪打开窗口的外部对象。像你的旧系统一样,自我保留的对象打破了对象所有权的基本点,使得很难找到东西(例如“给我一个打开的窗口列表”)。只是“漂浮”在那里的非单身人士经常会回来在你的建筑中咬你(我必须经常解决这个问题)。

尽管如此,有时自我所有权至少是方便的,最糟糕的是不是世界末日。所以自己拥有。唯一的区别是你需要明确地做,而不是匹配泄漏和过度释放(这是你的旧代码正在做的事情)。

创建私有strong属性。为其分配self。这将创建一个保留循环,在您将属性设置为nil之前将其保持不变。

答案 1 :(得分:0)

没有黑客,除了在其他对象中强烈引用对象之外,没有优雅的方法来保留对象。例如,您可以保留静态NSMutableArray / NSMutableSet,在那里添加控制器,然后在windowsWillClose:中将其删除。这比发布通知要短。为了使这个可重用,请创建一个带有数组的WindowControllerRegistry单例,在这里添加像这样的控制器,它将自动侦听NSWindowWillCloseNotification并将其从数组中删除,从而释放所有权。

作为一种快速解决方法,您可以non-ARC file执行retain / autorelease次来电:

my_retain(self);
my_autorelease(self);

// ArcDisabled.mm
void my_retain(id obj) { [obj retain]; }
void my_autorelease(id obj) { [obj autorelease]; }

答案 2 :(得分:0)

我认为您的替代方法应该是正确的,但我认为您不需要第二次通知。你应该能够做到:

- (void)windowWillClose:(NSNotification *)notification
{
    [proposalWindowArray removeObjectIdenticalTo:self];
}

假设“proposalWindowArray”是静态NSMutableArray。

答案 3 :(得分:0)

当我切换到ARC时,我遇到了同样的问题。您的解决方案有效,但您将其变得过于复杂。你可以基本上做你以前做过的事情,让窗户在关闭时释放,但是以ARC兼容的方式。

解决方案是在类本身内简单地创建类的属性。对于您的示例,在DetailWindowController中,您将添加以下属性:

@property (strong)  DetailWindowController      *theWindowController;

然后,当您使用上面的代码创建窗口时,添加一行,如下所示:

DetailWindowController *proposalWindowController = [[DetailWindowController alloc] initWithWindowNibName:@"ThePorposalWindow"];
[preferenceController setTheWindowController:proposalWindowController];
[proposalWindowController showWindow:nil];

最后,让ARC在关闭时释放窗口,就像在自动释放前使用ARC一样,在DetailWindowController类中,只需执行:

- (void)windowWillClose:(NSNotification *)notification
{
    // Let ARC tear this down and clean it up
    [self setTheWindowController:nil];
}