好的,所以 Apple 为我们带来了 ARC,这很棒。将我的应用程序重构为 ARC 后,几乎一切都工作正常,并且现在开发和维护变得更加容易。
只有一个问题我仍然无法弄清楚。
我的工作管理程序在自己的窗口中显示提案、订单等的不同详细信息。因此,我有一个特殊的类,其中 WindowControllers 被分配并使用 initWithWindowNibName 启动,然后使用 showWindow 显示窗口:
DetailWindowController *proposalWindowController = [[DetailWindowController alloc] initWithWindowNibName:@"ThePorposalWindow"];
[proposalWindowController showWindow:nil];
在 ARC 之前,WindowController 的实例进行了释放,如 文档:
- (void)windowWillClose:(NSNotification *)notification
{
[self autorelease];
}
但是现在有了 ARC,这不再可能了,更糟糕的是,在我的特殊类中,分配了 WindowController 并启动后,由于没有指向 windowController 的指针,ARC 释放了同一个 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]];
}
它有效,但我仍然不相信这是正确的方法。
有人有同样的问题或有改善的建议吗?
OK, so Apple brought ARC to us, which is great. After refactoring my Application to ARC almost everything works fine and it is a lot easier now to develop and maintain.
There is just one problem I still can't figure out.
My job management program shows different detail information of proposals, orders and so on in their own windows. So I have a special class where WindowControllers gets allocated and initiated with initWithWindowNibName and then the window is shown with showWindow:
DetailWindowController *proposalWindowController = [[DetailWindowController alloc] initWithWindowNibName:@"ThePorposalWindow"];
[proposalWindowController showWindow:nil];
Before ARC the Instance of the WindowController did the release like shown in the documentation:
- (void)windowWillClose:(NSNotification *)notification
{
[self autorelease];
}
But now with ARC this is not possible anymore and what makes it even worse, in my special class where the WindowController is allocated and initiated, the same windowController is released by ARC because there is no pointer to the windowController.
My idea was to copy the windowController into an mutuable array:
[proposalWindowArray addObject:proposalWindowController];
[[proposalWindowArray lastObject] showWindow:nil];
And in the windowControllers delegate method windowWillClose I post a notification to my special class:
- (void)windowWillClose:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"ProposalWindowWillClose" object:[[self window] windowController] userInfo:nil];
}
In my special class I listen to the notification and remove the object from the array:
- (void) proposalWindowWasClosed: (NSNotification *) notification
{
[proposalWindowArray removeObjectIdenticalTo:[notification object]];
}
It works, but I still do not believe that this is the correct way.
Does anybody has the same problem or a tip to make it better?
发布评论
评论(4)
我可能会使用委托方法而不是通知。一般来说,最好有一个外部对象来跟踪打开的窗口。自保留对象,就像你的旧系统一样,打破了对象所有权的基本点,并使查找东西变得困难(例如“给我一个打开的窗口的列表”)。只是“漂浮”在那里的非单例经常会回来咬你的架构(我必须经常修复这个问题)。
也就是说,有时自我拥有至少是方便的,最坏的情况也不是世界末日。如此自有。唯一的区别是您需要显式地执行此操作,而不是匹配泄漏和过度释放(这就是您的旧代码所做的)。
创建私有
strong
属性。将self
分配给它。这将创建一个保留循环,该循环将一直保留到您将属性设置为nil
。I'd probably use a delegate approach rather than notifications. Generally it is better to have an external object that keeps track of the open windows. Self-retaining objects, like your old system, break the basic points of object ownership and make it hard to find things (such as "give me a list of open windows"). Non-Singletons that are just "floating" out there often come back to bite you in your architecture (I've had to fix this often enough).
That said, sometimes self-ownership is at least convenient, and at worst not-the-end-of-the-world. So self-own. The only difference is that you need to do it explicitly rather than matching a leak and an over-release (which is what your old code was doing).
Create a private
strong
property. Assignself
to it. That will create a retain loop that will keep you around until you set the property tonil
.我认为您的替代方法应该是正确的,但我认为您不需要第二次通知。您应该能够执行以下操作:
假设“proposalWindowArray”是静态 NSMutableArray。
I think your alternative approach should be correct, but I don't think you need the second notification. You should be able to do:
Assuming the "proposalWindowArray" is a static NSMutableArray.
如果没有黑客,除了在其他对象中对某个对象进行强引用之外,就没有优雅的方法来保留该对象。例如,您可以保留静态
NSMutableArray
/NSMutableSet
,在其中添加控制器,然后在windowsWillClose:
中删除它。这比发布通知要短。为了使其可重用,请创建一个带有数组的 WindowControllerRegistry 单例,您可以在其中添加像这样的控制器,并且它将自动侦听 NSWindowWillCloseNotification 并将它们从数组中删除,从而释放所有权。作为一种快速解决方法,您可以从 非 ARC 文件:
Without hacks, there is no elegant way to keep an object retained other than having a strong reference to it in some other object. For example, you could keep a static
NSMutableArray
/NSMutableSet
, add your controller there, and remove it inwindowsWillClose:
. This will be shorter than posting a notification. To make this reusable, create aWindowControllerRegistry
singleton with an array, where you add controllers like this one, and which will automatically listen toNSWindowWillCloseNotification
and remove them from its array thus releasing ownership.As a quick workaround, you could perform
retain
/autorelease
calls from non-ARC file:当我切换到 ARC 时,我也遇到了同样的问题。你的解决方案有效,但你让它变得太复杂了。您基本上可以通过让窗口在关闭时自行释放来完成之前所做的事情,但采用 ARC 兼容的方式。
解决方案是简单地在类本身中创建类的属性。对于您的示例,在 DetailWindowController 中,您将添加以下属性:
然后,当您使用上面的代码创建窗口时,添加一行,如下所示:
最后,让 ARC 在关闭窗口时释放该窗口,就像使用自动释放一样pre-ARC,在 DetailWindowController 类中,只需执行以下操作:
I had this same issue when I switched to ARC. Your solution works, but you're making it too complicated. You can essentially do what you were doing before by having the window release itself when it closes, but in an ARC compatible manner.
The solution is to simply create a property of your class within the class itself. For your example, in DetailWindowController, you would add the following property:
Then when you create the window with your code above, add one line like so:
Then finally, to have ARC release the window when it is closed like you did with the autorelease pre-ARC, in the DetailWindowController class, simply do: