6

我将把一个非常常见的情况提炼成一般形式。假设我正在构建一些关闭的库对象,执行一些异步工作,然后在完成后回调委托方法。现在,还出于某种任意原因说我不能使用 ARC 或块进行回调。这是老式的。我们称这个对象为 Worker。

现在说在各种应用程序中还有其他几个类,除了它的公共接口之外,它们对 Worker 一无所知。他们利用工人达到自己的目的。我们称这些类为消费者。

说 Worker 像这样进行委托回调:

// "Private" method called internally when work is done.
- (void)somethingFinished
{
    [self.delegate workerDidFinish];
    [self someTask];
}

并说一些特定的消费者像这样处理回调:

- (void)workerDidFinish
{
    // Assume "worker" is a retain property to a Worker
    // instance that we previously created and began working,
    // and that it's also the sender of the message.
    self.worker = nil;
    // Other code...
}

现在,如果没有其他东西保留了那个特定的 Worker 实例,我们就有麻烦了。Worker 将被释放,然后控制权将返回到它的-somethingFinished方法,然后它将发送-someTask到回收或垃圾内存,并可能崩溃。没有人公然违反任何内存管理规则。

我不是在这里寻求技术解决方案。我知道几种选择。我想知道修复的责任落在谁身上。作为组件设计者,我是否应该实现 Worker 的-somethingFinished方法,以便在方法的持续时间内延长 Worker 的生命周期,就像[[self retain] autorelease]在开始时一样?或者,作为组件的使用者,我是否应该意识到我可能会在实例方法的中途吹走一个对象,然后等到稍后再释放它?

这个问题的答案似乎都表明从回调中释放对象是一个坏主意。不幸的是,关于 Worker(在本例中为 CLLocationManager)究竟是如何传递给委托的,这个问题中有很多令人分心的信息,而我在这里故意避免了这些信息。这个问题遇到了同样的情况,并提供了另一种解决方案。

就个人而言,我看不出如何追究消费者的责任。它没有违反任何内存管理规则,并且礼貌地使用了 Worker 的公共接口。它只是在不再需要时释放一个实例。但另一方面,这是否意味着任何可能以某种方式在中间方法中被释放的对象都需要人为地延长其自身的生命周期?毕竟,委托方法并不是消息发送者最终在方法中间被释放的唯一方式。

那么最终,谁负责修复?工人?消费者?它可以规范地确定吗?

4

2 回答 2

1

我认为这个例子中的负担在工人身上。我看到的问题是 Worker 对象在告诉其 Consumer 其工作已完成后正在内部做某事。Worker 只是为了消费者而存在,所以如果消费者的目标得到满足,为什么 Worker 仍然在做对消费者没有价值的事情呢?如果在“消耗性”工作完成后需要完成内部任务,则这些任务不适合放置在 Worker 对象的实例中,但可能应该由易失性较小的库类拥有的另一个内部对象完成不会被消费者的行为解除分配。

于 2012-11-19T22:58:53.533 回答
0

当代理收到通知时,应该开始观察工作人员并仅在 somethingFinushed 方法终止时释放它。

于 2012-11-19T22:58:08.523 回答