如何正确地通知委托人该实例不再需要? [英] How to correctly notify a delegate that the instance is no longer needed?

查看:78
本文介绍了如何正确地通知委托人该实例不再需要?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的模式:

1)SpecialView创建一个MessageView并对其进行强有力的引用.

1) SpecialView creates a MessageView and holds a strong reference to it.

2)用户在MessageView中点击一个按钮,使其淡出.然后,MessageView告诉它的委托SpecialView,它完全消失了.

2) User taps a button in MessageView which causes it to fade out. MessageView then tells it's delegate, SpecialView, that it faded out completely.

3)SpecialView发布MessageView.

3) SpecialView releases MessageView.

问题是这样的:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    [self.delegate messageViewFadedOut:self]; // delegate releases us...
    // self maybe got deallocated... BOOM!
    // now what? method of a zombie returns? stack freaks out?
} // does it even return?

在最后一行中,我调用了代理,该代理又立即释放MessageView. -fadedOut:finished:context:由核心动画didStopSelector回调调用.

In the last line I'm calling the delegate, which in turn immediately releases MessageView. -fadedOut:finished:context: is called by a core animation didStopSelector callback.

我担心的是,在-fadedOut:finished:context:完全返回之前,MessageView实例将被立即释放,从而导致非常讨厌的随机错误

My fear is that the MessageView instance is going to be deallocated immediately before the -fadedOut:finished:context: fully returned, causing very nasty random bugs

很久以前,一位资深的老程序员告诉我:切勿剪掉您所坐的树枝."

Once upon a time, a old veteran programmer told me: "Never cut the branch on which you're sitting on."

因此,为了确保实例在此方法返回之前一直存在,我在调用委托之前做了一次retain-autorlease-dance:

So in order to make sure the instance survives until this method returns, I made a retain-autorlease-dance before calling the delegate:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    //[[self retain] autorelease];
    [self.delegate messageViewFadedOut:self]; // delegate releases us...
}

但是,在ARC中,不再允许保留自动释放的舞蹈(迁移工具将不允许),并且似乎没有任何方法可以迫使ARC系统执行类似的操作.

However, under ARC, retain-autorelease dances are not allowed anymore (the migration tool won't allow it) and there seems to be no way to force the ARC system to do something like this.

所以我想出了这个策略:

So I came up with this strategy instead:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    [self.delegate performSelector:@selector(messageViewFadedOut:) withObject:self afterDelay:0];
}

延迟的performSelector有望使方法完全返回.据我所知,延迟为0仍然可以确保选择器在下一次运行循环迭代中执行,而不是立即执行.

The delayed performSelector hopefully lets the method fully return. As far as I know a delay of 0 still guarantees that the selector is performed in the next run loop iteration rather than immediately.

这很有可能也是伪造的.

There's a good chance this is bogus as well.

我该如何正确地解决这个问题,即一个对象要求另一个对象销毁对它的最后一个引用,从而有可能在调用另一个对象的方法有机会完全返回之前将对象重新分配?会有像堆栈跟踪僵尸这样的东西吗?

How can I correctly resolve this problem of one object asking another to destroy the last reference to it with the chance that the object get's deallocated before the method that made the call to the other object has a chance to fully return? Can there be something like a stack trace zombie?

我该如何在ARC下解决类似问题?

And how must I solve something like this under ARC?

推荐答案

老实说,我认为与其尝试模拟一个保留自动释放功能,还不如尝试调用委托方法messageViewFadedOut:您不在乎是否已释放对消息视图的拥有引用. willFadeOut: 方法的协定可能会假设它不会被释放,但是 fadedOut:didFadeOut: 方法对于被释放的对象应该可以.

To be honest, I think that rather than trying to emulate a retain-autorelease, you should make sure that by the time the delegate method messageViewFadedOut: is called you don't care if the owning reference to your message view is released. The contract for a willFadeOut: method may assume it won't be deallocated, but a fadedOut: or didFadeOut: method should be okay with the object being deallocated.

对于您的dealloc方法,一种理想的解决方案是通过取消正在发生的任何活动淡出动画(在某处保留对其的引用)来专门避免您所讨厌的讨厌的随机错误.这样一来,您就不必关心它到达dealloc的方式或时间,因为dealloc知道做X可以防止死后留下任何对象状态或视觉异常.

An ideal solution would be for your dealloc method to specifically avoid the nasty random bugs you are dreading, by cancelling any active fadeout animation that is occurring (hold a reference to it somewhere). That way you don't care how or when it gets to dealloc, because dealloc knows to do X to prevent leaving any object state or visual anomalies behind when it dies.

因此,只需使用您的解决方案(performSelector:withObject:afterDelay:)或GCD块:

So just use your solution (performSelector:withObject:afterDelay:) or maybe a GCD block:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 250 * NSEC_PER_MSEC), // 250ms
                   dispatch_get_current_queue(),
                   ^{
                        [self.delegate messageViewFadedOut:self];
                   });
}

此外,ARC可能会立即autorelease,为什么不多次测试该代码段并查看会发生什么呢?在dealloc中放置一个断点,并在方法返回之前查看是否已调用该断点.

Besides, ARC might just autorelease immediately, why don't you test that code section a bunch of times and see what happens? Put a breakpoint in dealloc and see if it's called before the method returns.

这篇关于如何正确地通知委托人该实例不再需要?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆