在委托回调期间,应该如何延长委托对象的寿命



我将把一个非常常见的情况提炼成一个通用的形式。比如说,我正在构建一些库对象,它会关闭,做一些异步工作,然后在完成后回调委托方法。现在,出于某种任意的原因,我不能使用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的公共接口。它只是在不再需要的时候释放一个实例。但另一方面,这是否意味着任何可能在方法中期以某种方式被释放的对象都需要人为地延长其寿命?毕竟,委托方法并不是消息发送方最终在方法中间解除分配的唯一方法。

那么,最终谁来负责修复呢?工人消费者它能被规范地确定吗?

我认为这个例子中的负担在Worker身上。我看到的问题是Worker对象在告诉它的Consumer它的工作已经完成之后在内部做一些事情。工人的存在只是为了消费者,所以如果消费者的目标得到了满足,为什么工人仍在做对消费者没有价值的事情?如果有内部任务需要在"可消耗"工作完成后完成,那么这些任务不适合放在Worker对象的实例中,但可能应该由不太稳定的库类所拥有的另一个内部对象完成,该库类不会被Consumer的操作解除锁定。

当委托收到通知时,应开始观察工作者,并仅在somethingFinushed方法终止时释放它。

最新更新